/*
  Losu Copyright Notice
  --------------------
    Losu is an open source programming language project under the MIT license
  that can be used for both academic and commercial purposes. There are no
  fees, no royalties, and no GNU-like "copyright" restrictions. Losu qualifies
  as open source software. However, Losu is not public property, and founder
  'chen-chaochen' retains its copyright.

    Losu has been registered with the National Copyright Administration of the
  People's Republic of China, and adopts the MIT license as the copyright
  licensing contract under which the right holder conditionally licenses its
  reproduction, distribution, and modification rights to an unspecified public.

    If you use Losu, please follow the public MIT agreement or choose to enter
  into a dedicated license agreement with us.

  The MIT LICENSE is as follows
  --------------------
  Copyright  2020 - now  chen-chaochen

    Permission is hereby granted, free of charge, to any person obtaining a
  copy of this software and associated documentation files (the “Software”), to
  deal in the Software without restriction, including without limitation the
  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  sell copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*/

/*
  This is the syntax analysis code for Losu, the complete compiler
  implementation, consisting of Lexer, Parser & Codegen. Parses script code
  written using Losu and converts it to in-memory bytecode form
*/

#include "losu_syntax.h"
#include "losu_bytecode.h"
#include "losu_errmsg.h"
#include "losu_gc.h"
#include "losu_malloc.h"
#include "losu_object.h"
#include "losu_vm.h"
#include <ctype.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef define_source_losusyntax_staticseg
#define define_source_losusyntax_staticseg
/* static segment */

/* IO */
static void __losuSyntaxError (_syntaxLex *lex, const char *msg, ...);

/* Lexer */
static void __losuSyntaxLexSetin (LosuVm *vm, _syntaxLex *lex, _syntaxIO *io,
                                  _inlineString *src);
static int16_t __losuSyntaxLexNext (_syntaxLex *lex, _syntaxTkvalue *tkv);
static void __losuSyntaxLexTtS (int16_t tk, char *s);

/* Parser */
static void __losuSyntaxParError (_syntaxLex *lex, int16_t tk);
static void __losuSyntaxParNewfunc (_syntaxLex *lex, _syntaxFunc *func);
static void __losuSyntaxParDelfunc (_syntaxLex *lex);
static void __losuSyntaxParNext (_syntaxLex *lex);
static _l_bool __losuSyntaxParCheckBlock (int16_t tk);
static void __losuSyntaxParCheck (_syntaxLex *lex, int16_t tk);
static void __losuSyntaxParCheckCondtion (_syntaxLex *lex, _l_bool c,
                                          const char *s);
static void __losuSyntaxParCheckMatch (_syntaxLex *lex, int16_t l, int16_t r,
                                       int32_t line);
static _inlineString *__losuSyntaxParCheckName (_syntaxLex *lex);
static void __losuSyntaxParCheckLimit (_syntaxLex *lex, int32_t v, int32_t l,
                                       const char *errmsg);

static void __losuSyntaxParNewlcvar (_syntaxLex *lex, _inlineString *name,
                                     int16_t i);
static void __losuSyntaxParRemovelcvar (_syntaxLex *lex, int16_t i);
static _l_bool __losuSyntaxParStat (_syntaxLex *lex);
static void __losuSyntaxParStatIf (_syntaxLex *lex, int32_t line);
static void __losuSyntaxParStatWith (_syntaxLex *lex, int32_t line);
static void __losuSyntaxParStatBlock (_syntaxLex *lex);
static void __losuSyntaxParStatFor (_syntaxLex *lex, int32_t line);
static void __losuSyntaxParStatLoop (_syntaxLex *lex, int32_t line);
static void __losuSyntaxParStatUntil (_syntaxLex *lex, int32_t line);
static void __losuSyntaxParStatFunc (_syntaxLex *lex, int32_t line);
static void __losuSyntaxParStatVar (_syntaxLex *lex);
static void __losuSyntaxParStatName (_syntaxLex *lex);
static void __losuSyntaxParStatReturn (_syntaxLex *lex);
static void __losuSyntaxParStatBreak (_syntaxLex *lex);
static void __losuSyntaxParEnterbreak (_syntaxFunc *func, _syntaxBreak *br);
static void __losuSyntaxParLeavebreak (_syntaxFunc *func, _syntaxBreak *br);
static void __losuSyntaxParStatForNum (_syntaxLex *lex, _inlineString *vname);
static void __losuSyntaxParStatForObj (_syntaxLex *lex, _inlineString *vname);
static void __losuSyntaxParStatForBody (_syntaxLex *lex, _l_bool isO);
static _l_bool __losuSyntaxParStatFuncName (_syntaxLex *lex, _syntaxExp *v);
static void __losuSyntaxParStatFuncBody (_syntaxLex *lex, _l_bool nself,
                                         int32_t line);
static void __losuSyntaxParStatFuncParlist (_syntaxLex *lex);
static int32_t __losuSyntaxParStatNameAssment (_syntaxLex *lex, _syntaxExp *v,
                                               int32_t nvar);
static int32_t __losuSyntaxParExplist (_syntaxLex *lex);
static void __losuSyntaxParAdStack (_syntaxLex *lex, int32_t nv, int32_t ne);
static void __losuSyntaxParAdLcvar (_syntaxLex *lex, int32_t nv);
static void __losuSyntaxParVarFunc (_syntaxLex *lex, _syntaxExp *v);
static void __losuSyntaxParExp (_syntaxLex *lex);
static void __losuSyntaxParSvar (_syntaxLex *lex, _inlineString *n,
                                 _syntaxExp *v);
static int32_t __losuSyntaxParStrconst (_syntaxFunc *func, _inlineString *s);
static int32_t __losuSyntaxParSubExp (_syntaxLex *lex, _syntaxExp *v, int l);
static void __losuSyntaxParExpFargs (_syntaxLex *lex, _l_bool slf);
static int32_t __losuSyntaxParExpVarlevel (_syntaxLex *lex, _inlineString *n,
                                           _syntaxExp *v);
static void __losuSyntaxParSimpleExp (_syntaxLex *lex, _syntaxExp *v);
static void __losuSyntaxParUnitConstructor (_syntaxLex *lex);
static int32_t __losuSyntaxParUnitMapfield (_syntaxLex *lex);
static int32_t __losuSyntaxParUnitListfield (_syntaxLex *lex);

/* Codegen */
static int32_t __losuSyntaxCgenCodearg (_syntaxFunc *func, vmIns_OP o,
                                        int32_t arg1, int32_t arg2);
static void __losuSyntaxCgenConcat (_syntaxFunc *func, int32_t *l1,
                                    int32_t l2);
static int32_t __losuSyntaxCgenJump (_syntaxFunc *func);
static void __losuSyntaxCgenPalist (_syntaxFunc *func, int32_t list,
                                    int32_t target);
static int32_t __losuSyntaxCgenGetL (_syntaxFunc *func);
static void __losuSyntaxCgenGoT (_syntaxFunc *func, _syntaxExp *v,
                                 int32_t keep);
static void __losuSyntaxCgenGoF (_syntaxFunc *func, _syntaxExp *v,
                                 int32_t keep);
static void __losuSyntaxCgenTostack (_syntaxLex *lex, _syntaxExp *v,
                                     int32_t o);
static void __losuSyntaxCgenAdStack (_syntaxFunc *func, int32_t n);
static void __losuSyntaxCgenSetVar (_syntaxLex *lex, _syntaxExp *var);
static _l_bool __losuSyntaxCgenIsopen (_syntaxFunc *func);
static void __losuSyntaxCgenSetNcallr (_syntaxFunc *func, int32_t nres);
static void __losuSyntaxCgenNumber (_syntaxFunc *func, _l_number f);
static void __losuSyntaxCgenDtStack (_syntaxFunc *func, int32_t dt);
static void __losuSyntaxCgenPrefix (_syntaxLex *lex, vmIns_UnOp op,
                                    _syntaxExp *v);
static void __losuSyntaxCgenInfix (_syntaxLex *lex, vmIns_BinOp op,
                                   _syntaxExp *v);
static void __losuSyntaxCgenPosfix (_syntaxLex *lex, vmIns_BinOp op,
                                    _syntaxExp *v1, _syntaxExp *v2);
static int32_t __losuSyntaxCgenGetJump (_syntaxFunc *func, int32_t pc);
static void __losuSyntaxCgenFixJump (_syntaxFunc *func, int32_t pc,
                                     int32_t dt);
static void __losuSyntaxCgenPlistfunc (_syntaxFunc *func, int32_t list,
                                       int32_t tg, vmIns_OP ins,
                                       int32_t instg);
static void __losuSyntaxCgenGo (_syntaxFunc *func, _syntaxExp *v, int32_t inv,
                                vmIns_OP jump);
static _l_bool __losuSyntaxCgenDischarge (_syntaxFunc *func, _syntaxExp *v);
static _l_bool __losuSyntaxCgenNeedval (_syntaxFunc *func, int32_t l,
                                        vmIns_OP v);
static vmIns_OP __losuSyntaxCgenJumpInvert (vmIns_OP op);

#endif /* define_source_losusyntax_staticseg */

#ifndef define_source_losusyntax_io
#define define_source_losusyntax_io

#define EOZ (-1)

int32_t
__losu_syntaxIO_doload (LosuVm *vm, _syntaxIO *io)
{
  /*   _l_gcint oldblock; */
  int32_t sta;
  __losu_gc_checkClt (vm);

  LosuObj *oldbase = vm->base;
  LosuObj *oldtop = vm->top;
  __longjump lj = {
    .err = 0,
    .pre = vm->errjmp,
  };
  vm->errjmp = &lj;
  if (setjmp (lj.jmpflag) == 0)
    {
      _inlineScode *fcd = io->bin ? __losu_syntaxIrload_load (vm, io)
                                  : __losu_syntaxParser_parse (vm, io);
      _inlineFunction *f = __losu_objFunc_new (vm, 0);
      ovtype ((vm->top)) = LosuTypeDefine_function;
      ovfunc ((vm->top)) = f;
      vm->top++;
      f->func.sdef = fcd;
      f->isC = 0;
    }
  else
    {
      vm->base = oldbase;
      vm->top = oldtop;
      if (vm->top - vm->stack < vm->stacksize - 1)
        vm->stackmax = vm->stack + (vm->stacksize - 1);
    }
  vm->errjmp = lj.pre;
  sta = lj.err;
  /* if (sta == 0)
    vm->gcDymax += (vm->nblocks - oldblock);
  else  */
  if (sta == LosuErrorCode_Runtime)
    sta = LosuErrorCode_Syntax;
  return sta;
}

int32_t
__losu_syntaxIO_loadfile (LosuVm *vm, const char *fn)
{
  _syntaxIO io = { 0 };
  int32_t sta;
  FILE *f = fopen (fn, "rb");
  if (f == NULL)
    {
      vm_error (vm, LosuErrorCode_File,
                __config_losucore_errmsg_msgfileNotFound, fn);
      return LosuErrorCode_File;
    }
  __losu_syntaxIO_openH (&io, (void *)f, fn);

  /* bin or txt */
  int32_t c = fgetc (f);
  if (c == 0) /* bin */
    io.bin = 1;
  ungetc (c, f);

  const char *on = vm->name;
  vm->name = fn;
  sta = __losu_syntaxIO_doload (vm, &io);
  vm->name = on;
  fclose (f);
  return sta;
}

int32_t
__losu_syntaxIO_loadstring (LosuVm *vm, const char *str, _l_size_t len,
                            const char *name)
{
  _syntaxIO io = { 0 };
  __losu_syntaxIO_openS (&io, str, len, name);

  /* bin or txt */
  if (io.p[0] == 0 && len > 0)
    io.bin = 1;

  const char *on = vm->name;
  vm->name = name;
  int32_t sta = __losu_syntaxIO_doload (vm, &io);
  vm->name = on;
  return sta;
}

int16_t
__losu_syntaxIOS_fillbuff (_syntaxIO *io)
{
  return EOZ;
}
int16_t
__losu_syntaxIOH_fillbuff (_syntaxIO *io)
{
  _l_size_t n = 0;
  if (feof ((FILE *)(io->h)))
    return EOZ;
  n = fread (io->buff, sizeof (char), __config_losucore_vm_iobuff,
             (FILE *)(io->h));
  if (!n)
    return EOZ;
  io->size = n - 1;
  io->p = io->buff;
  return (int16_t)(*(io->p++));
}

void
__losu_syntaxIO_openH (_syntaxIO *io, void *h, const char *name)
{
  if (h)
    {
      io->size = 0;
      io->p = io->buff;
      io->fillbuff = __losu_syntaxIOH_fillbuff;
      io->h = h;
      io->name = name;
    }
}

void
__losu_syntaxIO_openS (_syntaxIO *io, const char *p, _l_size_t size,
                       const char *name)
{
  io->size = (p == NULL) ? 0 : size;
  io->p = (const unsigned char *)p;
  io->fillbuff = __losu_syntaxIOS_fillbuff;
  io->name = name;
}

static void
__losuSyntaxError (_syntaxLex *lex, const char *msg, ...)
{
  memset (lex->vm->staticbuff, 0, sizeof (lex->vm->staticbuff));
  va_list ap;
  va_start (ap, msg);
  vsprintf ((char *)(lex->vm->staticbuff), msg, ap);
  fprintf (stderr, "Syntax Error: %s\n at line %d of '%s' \n",
           lex->vm->staticbuff, lex->linenumber,
           lex->io->name != NULL ? lex->io->name : "<unknown>");
  va_end (ap);
  __losu_vmHeap_break (lex->vm, LosuErrorCode_Syntax);
}

#undef EOZ
#endif /* define_source_losusyntax_io */

#ifndef define_source_losusyntax_lexer
#define define_source_losusyntax_lexer

/* declare segment */
#define EOZ -1
#define next(Lex) (Lex->current = __losu_syntaxIO_getc (Lex->io))
#define save(vm, c, l) (vm->bufftmp[l++] = (unsigned char)c)
#define save_next(vm, Lex, l) (save (vm, Lex->current, l), next (Lex))
#define incline(Lex) ((Lex->linenumber)++)
static void checkbuffer (LosuVm *vm, _l_size_t n, _l_size_t len);

/* data segment */
struct
{
  const char *str;
  int16_t key;
  int8_t idt; /* idt or not? */
} static const __keyword[] = {

  { "and", TOKEN_AND, 0 },
  { "not", TOKEN_NOT, 0 },
  { "or", TOKEN_OR, 0 },

  { "local", TOKEN_BLOCK, 1 },

  { "if", TOKEN_IF, 1 },
  { "else", TOKEN_ELSE, 1 },
  { "elif", TOKEN_ELSEIF, 1 },
  { "pass", TOKEN_END, -1 },

  { "def", TOKEN_FUNCTION, 1 },
  { "...", TOKEN_ARG, 0 },

  { "var", TOKEN_VAR, 0 },
  { "null", TOKEN_NULL, 0 },

  { "return", TOKEN_RETURN, 0 },
  { "break", TOKEN_BREAK, 0 },

  { "with", TOKEN_WITH, 1 },
  { "until", TOKEN_UNTIL, 1 },
  { "loop", TOKEN_LOOP, 0 },
  { "to", TOKEN_TO, 0 },

  { "for", TOKEN_FOR, 1 },

  { "==", TOKEN_EQ, 0 },
  { ">=", TOKEN_GE, 0 },
  { "<=", TOKEN_LE, 0 },
  { "!=", TOKEN_NE, 0 },
  { "!=", TOKEN_NE, 0 },
  { "&", TOKEN_CONCAT, 0 },

#ifdef __config_losucore_feature_chKeyword
  { "且", TOKEN_AND, 0 },
  { "非", TOKEN_NOT, 0 },
  { "或", TOKEN_OR, 0 },

  { "如果", TOKEN_IF, 0 },
  { "否则", TOKEN_ELSE, 0 },
  { "另外", TOKEN_ELSEIF, 0 },

  { "定义", TOKEN_FUNCTION, 0 },

  { "令", TOKEN_VAR, 0 },
  { "空", TOKEN_NULL, 0 },

  { "返回", TOKEN_RETURN, 0 },
  { "跳出", TOKEN_BREAK, 0 },

  { "满足", TOKEN_WITH, 0 },
  { "直到", TOKEN_UNTIL, 0 },
  { "重复", TOKEN_LOOP, 0 },
  { "至", TOKEN_TO, 0 },

  { "计次", TOKEN_FOR, 0 },

  /* Only chKeyword */
  { "__极值__", TOKEN_FOR_MAX, 0 },
  { "__步幅__", TOKEN_FOR_STEP, 0 },
  { "__此__", TOKEN_FOR_THIS, 0 },
  { "此", TOKEN_THIS, 0 },
  { "构造", TOKEN_CONST, 0 },
  { "变参", TOKEN_VARARG, 0 },
  { "属", TOKEN_IN, 0 },
#endif

};

/* code segment */
void
checkbuffer (LosuVm *vm, _l_size_t n, _l_size_t len)
{
  _l_size_t nlen = n + len;
  if (nlen <= vm->nbufftmp)
    return;
  __losu_mem_reallocvector (vm, vm->bufftmp, nlen, unsigned char);
  vm->nblocks += (nlen - vm->nbufftmp) * sizeof (char);
  vm->nbufftmp = nlen;
}

void
__losu_syntaxLex_init (LosuVm *vm)
{
  for (int16_t i = 0; i < sizeof (__keyword) / sizeof (__keyword[0]); i++)
    {
      _inlineString *s = __losu_objString_new (vm, __keyword[i].str);
      s->marked = __keyword[i].key;
    }
}

static void
__losuSyntaxLexTtS (int16_t tk, char *s)
{
  if (tk < 256)
    {
      s[0] = (unsigned char)tk;
      s[1] = '\0';
    }
  else
    {
      int16_t i;
      for (i = 0; i < sizeof (__keyword) / sizeof (__keyword[0]); i++)
        if (__keyword[i].key == tk)
          break;
      strcpy (s, __keyword[i].str);
    }
}

static void
__losuSyntaxLexSetin (LosuVm *vm, _syntaxLex *lex, _syntaxIO *io,
                      _inlineString *src)
{
  lex->vm = vm;
  lex->tkahead.token = TOKEN_EOZ;
  lex->io = io;
  lex->fs = NULL;
  lex->lastline = lex->linenumber = 1;
  lex->source = src;
  next (lex);
}

static uint8_t
__utf8CheckLen (uint8_t c)
{
  /** 单字节序列的 leader byte 总是在（0-127）范围内。
   * 两字节序列的 leader byte 在（194-223）范围内。
   * 三字节序列的 leader byte 在（224-239）范围内。
   * 四字节序列的 leader byte 在（240-247）范围内。
   * */
  uint8_t len = 0;
  if (c < 0x80)
    { /* then UTF-8   单字节 */
      len = 1;
    }
  else if (c >= 0xC2 && c <= 0xDF)
    { /* then 首字节   UTF-8 占用2个字节 */
      len = 2;
    }
  else if (c >= 0xE0 && c <= 0xEF)
    { /* then 首字节   UTF-8 占用3个字节 */
      len = 3;
    }
  else if (c >= 0xF0 && c <= 0xF7)
    { /* then 首字节   UTF-8 占用4个字节 */
      len = 4;
    }

  return len;
}

static unsigned char *
__lexReadname (_syntaxLex *lex)
{
  LosuVm *vm = lex->vm;
  _l_size_t l = 0;
  do
    {
      uint8_t len = __utf8CheckLen ((uint8_t)(lex->current));
      for (uint8_t i = 0; i < len; i++)
        {
          checkbuffer (vm, l, 32);
          save_next (vm, lex, l);
        }
    }
  while (isalnum (lex->current) || lex->current == '_'
         || __utf8CheckLen ((uint8_t)(lex->current)) > 1);
  save (vm, '\0', l);
  return vm->bufftmp;
}

static void
__lexReadnumber (_syntaxLex *lex, _l_bool dot, _syntaxTkvalue *tkv)
{
  LosuVm *vm = lex->vm;
  _l_size_t l = 0;
  checkbuffer (vm, l, 32);
  if (dot)
    save (vm, '.', l);
  while (isdigit (lex->current))
    {
      checkbuffer (vm, l, 32);
      save_next (vm, lex, l);
    }
  if (lex->current == '.')
    {
      save_next (vm, lex, l);
      if (lex->current == '.')
        {
          save (vm, '\0', l);
          __losuSyntaxError (lex, __config_losucore_errmsg_msgInvalidNumber,
                             vm->bufftmp);
        }
    }
  while (isdigit (lex->current))
    {
      checkbuffer (vm, l, 32);
      save_next (vm, lex, l);
    }
  if (lex->current == 'e' || lex->current == 'E')
    {
      save_next (vm, lex, l);
      if (lex->current == '+' || lex->current == '-')
        save_next (vm, lex, l);
      while (isdigit (lex->current))
        {
          checkbuffer (vm, l, 32);
          save_next (vm, lex, l);
        }
    }
  save (vm, '\0', l);
  if (!__losu_object_str2num ((const char *)vm->bufftmp, &tkv->num))
    __losuSyntaxError (lex, __config_losucore_errmsg_msgInvalidNumber,
                       vm->bufftmp);
}

static _l_bool
__lexReadstring (_syntaxLex *lex, uint8_t del, _syntaxTkvalue *tkv)
{
  LosuVm *vm = lex->vm;
  _l_size_t l = 0;
  checkbuffer (vm, l, 32);
  save_next (vm, lex, l);
  if (lex->current != del)
    {
      while (lex->current != del)
        {
          if (lex->current == EOZ || lex->current == '\n')
            __losuSyntaxError (lex, __config_losucore_errmsg_msgMissStrEnd,
                               del); /* missing terminating  character %c  */

          checkbuffer (vm, l, 32);

          if (lex->current == '%')
            {
              next (lex);
              uint8_t t = 0;
              if (!(('0' <= lex->current && lex->current <= '9')
                    || ('a' <= lex->current && lex->current <= 'f')
                    || ('A' <= lex->current && lex->current <= 'F')))
                __losuSyntaxError (
                    lex, __config_losucore_errmsg_msgInvalidEscapeHex);
              /* % used with no following hex digits */
              switch (lex->current)
                {
                case 'A':
                case 'a':
                  t = 16 * 10;
                  break;
                case 'B':
                case 'b':
                  t = 16 * 11;
                  break;
                case 'C':
                case 'c':
                  t = 16 * 12;
                  break;
                case 'D':
                case 'd':
                  t = 16 * 13;
                  break;
                case 'E':
                case 'e':
                  t = 16 * 14;
                  break;
                case 'F':
                case 'f':
                  t = 16 * 15;
                  break;

                default:
                  t = 16 * (lex->current - '0');
                }
              next (lex);
              if (!(('0' <= lex->current && lex->current <= '9')
                    || ('a' <= lex->current && lex->current <= 'f')
                    || ('A' <= lex->current && lex->current <= 'F')))
                __losuSyntaxError (
                    lex, __config_losucore_errmsg_msgInvalidEscapeHex);
              /* % used with no following hex digits */
              switch (lex->current)
                {
                case 'A':
                case 'a':
                  t += 10;
                  break;
                case 'B':
                case 'b':
                  t += 11;
                  break;
                case 'C':
                case 'c':
                  t += 12;
                  break;
                case 'D':
                case 'd':
                  t += 13;
                  break;
                case 'E':
                case 'e':
                  t += 14;
                  break;
                case 'F':
                case 'f':
                  t += 15;
                  break;

                default:
                  t += (lex->current - '0');
                }
              save (vm, (unsigned char)t, l);
              next (lex);
              continue;
            }

          if (lex->current == '\\')
            {
              next (lex);
              switch (lex->current)
                {
                case 'a':
                  save (vm, '\a', l);
                  next (lex);
                  break;
                case 'b':
                  save (vm, '\b', l);
                  next (lex);
                  break;
                case 'f':
                  save (vm, '\f', l);
                  next (lex);
                  break;
                case 'n':
                  save (vm, '\n', l);
                  next (lex);
                  break;
                case 'r':
                  save (vm, '\r', l);
                  next (lex);
                  break;
                case 't':
                  save (vm, '\t', l);
                  next (lex);
                  break;
                case 'v':
                  save (vm, '\v', l);
                  next (lex);
                  break;
                case '\\':
                  save (vm, '\\', l);
                  next (lex);
                  break;
                case '\'':
                  save (vm, '\'', l);
                  next (lex);
                  break;
                case '\"':
                  save (vm, '\"', l);
                  next (lex);
                  break;
                case '\r':
                  save (vm, '\n', l);
                  next (lex);
                  incline (lex);
                  if (lex->current == '\n')
                    next (lex);
                  break;
                case '\n':
                  save (vm, '\n', l);
                  next (lex);
                  incline (lex);
                  break;
                case 'u':
                  {
                    uint8_t i = 1, clen = 1;
                    volatile uint8_t t = 0;
                    while (1)
                      {

                        next (lex);
                        if (!(('0' <= lex->current && lex->current <= '9')
                              || ('a' <= lex->current && lex->current <= 'f')
                              || ('A' <= lex->current && lex->current <= 'F')))
                          __losuSyntaxError (
                              lex,
                              __config_losucore_errmsg_msgInvalidEscapeHex);
                        /* % used with no following hex digits */
                        switch (lex->current)
                          {
                          case 'A':
                          case 'a':
                            t = 16 * 10;
                            break;
                          case 'B':
                          case 'b':
                            t = 16 * 11;
                            break;
                          case 'C':
                          case 'c':
                            t = 16 * 12;
                            break;
                          case 'D':
                          case 'd':
                            t = 16 * 13;
                            break;
                          case 'E':
                          case 'e':
                            t = 16 * 14;
                            break;
                          case 'F':
                          case 'f':
                            t = 16 * 15;
                            break;

                          default:
                            t = 16 * (lex->current - '0');
                          }
                        next (lex);
                        if (!(('0' <= lex->current && lex->current <= '9')
                              || ('a' <= lex->current && lex->current <= 'f')
                              || ('A' <= lex->current && lex->current <= 'F')))
                          __losuSyntaxError (
                              lex,
                              __config_losucore_errmsg_msgInvalidEscapeHex);
                        /* % used with no following hex digits */
                        switch (lex->current)
                          {
                          case 'A':
                          case 'a':
                            t += 10;
                            break;
                          case 'B':
                          case 'b':
                            t += 11;
                            break;
                          case 'C':
                          case 'c':
                            t += 12;
                            break;
                          case 'D':
                          case 'd':
                            t += 13;
                            break;
                          case 'E':
                          case 'e':
                            t += 14;
                            break;
                          case 'F':
                          case 'f':
                            t += 15;
                            break;

                          default:
                            t += (lex->current - '0');
                          }
                        if (i == 1)
                          clen = __utf8CheckLen (t);
                        if (clen == 0)
                          {
                            __losuSyntaxError (
                                lex,
                                __config_losucore_errmsg_msgInvalidEscapeUtf8);
                            break;
                          }
                        save (vm, t, l);
                        if (i >= clen)
                          break;
                        i++;
                      }
                    next (lex);
                    break;
                  }
                default:
                  save_next (vm, lex, l);
                }
              continue;
            }
          save_next (vm, lex, l);
        }
      save_next (vm, lex, l);
      save (vm, '\0', l);
      tkv->s = __losu_objString_newstr (vm, (const char *)(vm->bufftmp) + 1,
                                        l - 3);
      return 0;
    }
  else
    {
      save_next (vm, lex, l);
      if (lex->current != del)
        {
          save (vm, '\0', l);
          tkv->s = __losu_objString_newstr (
              vm, (const char *)(vm->bufftmp) + 1, l - 3);
          return 0;
        }
      else
        {
          while (1)
            {
              next (lex);
              if (lex->current == '\n')
                (lex->linenumber)++;
              if (lex->current == EOZ)
                __losuSyntaxError (
                    lex, __config_losucore_errmsg_msgInvalidBlockComment);
              if (lex->current == del)
                {
                  next (lex);
                  if (lex->current == del)
                    {
                      next (lex);
                      if (lex->current == del)
                        {
                          next (lex);
                          return 1;
                        }
                    }
                }
            }
        }
    }
}

static void
__lexReadPurestring (_syntaxLex *lex, uint8_t del, _syntaxTkvalue *tkv)
{
  LosuVm *vm = lex->vm;
  _l_size_t l = 0;
  checkbuffer (vm, l, 32);
  save_next (vm, lex, l);
  while (lex->current != del)
    {
      if (lex->current == '\n' || lex->current == EOZ)
        __losuSyntaxError (lex, __config_losucore_errmsg_msgMissStrEnd, del);
      checkbuffer (vm, l, 32);
      save_next (vm, lex, l);
    }
  save_next (vm, lex, l);
  save (vm, '\0', l);
  tkv->s
      = __losu_objString_newstr (vm, (const char *)(vm->bufftmp) + 1, l - 3);
}

static int16_t
__losuSyntaxLexNext (_syntaxLex *lex, _syntaxTkvalue *tkv)
{
  if (lex->_syntaxLexIdt.tmp > 0)
    {
      lex->_syntaxLexIdt.tmp--;
      lex->_syntaxLexIdt.nowidt--;
      return TOKEN_END;
    }
  while (1)
    {

      switch (lex->current)
        {
        /* comment */
        case '#':
          {
            while (lex->current != '\n')
              {
                next (lex);
                if (lex->current == EOZ)
                  return TOKEN_EOZ;
              }
            break;
          }
        case ';':
          {
            next ((lex));
            continue;
          }
        /* line++ */
        case '\n':
          {
            next (lex);
            incline (lex);
            /* check idt */
            lex->_syntaxLexIdt.read = 0;
            uint8_t i = 0;
            while (1)
              {
                /* printf ("P:%c\n", lex->current == EOZ ? '@' : lex->current);
                 */
                switch (lex->current)
                  {
                  case '\n':
                    {
                      lex->_syntaxLexIdt.read = 0;
                      incline (lex);
                      break;
                    }
                  case ' ':
                    {
                      lex->_syntaxLexIdt.read++;
                      break;
                    }
                  case '\t':
                    {
                      lex->_syntaxLexIdt.read += lex->_syntaxLexIdt.size;
                      break;
                    }
                  default:
                    {
                      /* printf ("line:%d,idt:%d\n", lex->linenumber,
                              lex->_syntaxLexIdt.nowidt); */
                      i = 1;
                      /* if (lex->current == '}' || lex->current == ')')
                        {
                          i = 2;
                          lex->_syntaxLexIdt.nowidt--;
                        } */
                      if (lex->_syntaxLexIdt.read
                          < lex->_syntaxLexIdt.nowidt
                                * lex->_syntaxLexIdt.size) /* need idt */
                        {
                          if (lex->_syntaxLexIdt.read
                              % lex->_syntaxLexIdt.size) /* not muti */
                            __losuSyntaxError (
                                lex,
                                __config_losucore_errmsg_msgInvalidIdtMutiple,
                                lex->_syntaxLexIdt.size,
                                lex->_syntaxLexIdt.read);
                          lex->_syntaxLexIdt.tmp
                              = lex->_syntaxLexIdt.nowidt
                                - lex->_syntaxLexIdt.read
                                      / lex->_syntaxLexIdt.size;
                          if (lex->current == '}' || lex->current == ')')
                            lex->_syntaxLexIdt.tmp--;
                          if (lex->_syntaxLexIdt.tmp > 0)
                            {
                              lex->_syntaxLexIdt.tmp--;
                              lex->_syntaxLexIdt.nowidt--;
                              return TOKEN_END;
                            }
                        }
                      /* if (i == 2)
                        lex->_syntaxLexIdt.nowidt++; */
                      break;
                    }
                  }
                if (i)
                  break;
                next (lex);
              }
            continue;
          }
        case EOZ:
          {
            if (lex->_syntaxLexIdt.nowidt)
              {
                lex->_syntaxLexIdt.tmp = lex->_syntaxLexIdt.nowidt;
                lex->_syntaxLexIdt.tmp--;
                lex->_syntaxLexIdt.nowidt--;
                return TOKEN_END;
              }
            return TOKEN_EOZ;
          }
        /* case ':':
          {
            return ':';
          } */
        case '{':
          {
            next (lex);
            lex->_syntaxLexIdt.nowidt++;
            return '{';
          }
        case '}':
          {
            next (lex);
            lex->_syntaxLexIdt.nowidt--;
            return '}';
          }
        case '(':
          {
            next (lex);
            lex->_syntaxLexIdt.nowidt++;
            return '(';
          }
        case ')':
          {
            next (lex);
            lex->_syntaxLexIdt.nowidt--;
            return ')';
          }

        /* next */
        case '\r':
        case '\t':
        case ' ':
        case '\0':
          {
            next (lex);
            continue;
          }

        /* string */
        case '\'':
        case '\"':
          {
            if (__lexReadstring (lex, lex->current, tkv))
              continue;
            return TOKEN_STRING;
          }
        case '$':
          {
            next (lex);
            if (lex->current == '\'' || lex->current == '\"')
              {
                __lexReadPurestring (lex, lex->current, tkv);
                return TOKEN_STRING;
              }
            else
              __losuSyntaxError (
                  lex, __config_losucore_errmsg_msgInvalidPureString);
          }

        /* < = > */
        case '<':
          {
            next (lex);
            if (lex->current == '=')
              {
                next (lex);
                return TOKEN_LE;
              }
            else if (lex->current == '<')
              {
                next (lex);
                return TOKEN_BLOCK;
              }
            else
              return '<';
          }
        case '=':
          {
            next (lex);
            if (lex->current != '=')
              return '=';
            else
              {
                next (lex);
                return TOKEN_EQ;
              }
          }
        case '>':
          {
            next (lex);
            if (lex->current == '=')
              {
                next (lex);
                return TOKEN_GE;
              }
            /* else if (lex->current == '>')
              {
                next (lex);
                return TOKEN_ENDB;
              } */
            else
              return '>';
          }

        /* & or && */
        case '&':
          {
            next (lex);
#ifdef __config_losucore_feature_cStyle
            if (lex->current == '&')
              {
                next (lex);
                return TOKEN_AND;
              }
            else
#endif
              return TOKEN_CONCAT;
          }

        /* || */
        case '|':
          {
            next (lex);
#ifdef __config_losucore_feature_cStyle
            if (lex->current == '|')
              {
                next (lex);
                return TOKEN_OR;
              }
            else
#endif
              return '|';
          }

        /* != or ! */
        case '!':
          {
            next (lex);
            if (lex->current == '=')
              {
                next (lex);
                return TOKEN_NE;
              }

#ifdef __config_losucore_feature_cStyle
            else
              return TOKEN_NOT;
#endif
          }
        case '.':
          {
            next (lex);
            if (lex->current == '.')
              {
                next (lex);
                if (lex->current == '.')
                  {
                    next (lex);
                    return TOKEN_ARG;
                  }
                else
                  __losuSyntaxError (
                      lex, __config_losucore_errmsg_msgUnknownSymbol, "..");
              }
            if (isdigit (lex->current))
              {
                __lexReadnumber (lex, 1, tkv);
                return TOKEN_NUMBER;
              }
            else
              return '.';
          }

        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
          {
            __lexReadnumber (lex, 0, tkv);
            return TOKEN_NUMBER;
          }

        default:
          {
            if (!isalpha (lex->current) && lex->current != '_'
                && lex->current < 0x80)
              {
                int16_t c = lex->current;
                next (lex);
                return c;
              }
            _inlineString *ts = __losu_objString_new (
                lex->vm, (const char *)__lexReadname (lex));

            if (ts->marked > 255)
              {
                { // do idt
                  for (int32_t i = 0;
                       i < sizeof (__keyword) / sizeof (__keyword[0]); i++)
                    if (__keyword[i].key == ts->marked)
                      {
                        lex->_syntaxLexIdt.nowidt += __keyword[i].idt;
                        break;
                      }
                }
#ifdef __config_losucore_feature_chKeyword
                switch (ts->marked)
                  {
                  case TOKEN_THIS:
                    {
                      tkv->s = __losu_objString_new (lex->vm, "self");
                      return TOKEN_NAME;
                    }
                  case TOKEN_VARARG:
                    {
                      tkv->s = __losu_objString_new (lex->vm, "arg");
                      return TOKEN_NAME;
                    }
                  case TOKEN_FOR_MAX:
                    {
                      tkv->s = __losu_objString_new (lex->vm, "__MAX__");
                      return TOKEN_NAME;
                    }
                  case TOKEN_FOR_STEP:
                    {
                      tkv->s = __losu_objString_new (lex->vm, "__STEP__");
                      return TOKEN_NAME;
                    }
                  case TOKEN_FOR_THIS:
                    {
                      tkv->s = __losu_objString_new (lex->vm, "__THIS__");
                      return TOKEN_NAME;
                    }
                  case TOKEN_CONST:
                    {
                      tkv->s = __losu_objString_new (lex->vm, "__init__");
                      return TOKEN_NAME;
                    }
                  case TOKEN_IN:
                    {
                      tkv->s = __losu_objString_new (lex->vm, "in");
                      return TOKEN_NAME;
                    }
                  }

#endif

                return ts->marked;
              }
            tkv->s = ts;
            return TOKEN_NAME;
          }
        }
    }
}

/* undef segment */
#undef EOZ
#undef next
#undef save
#undef save_next
#undef incline

#endif /* define_source_losusyntax_lexer */

#ifndef define_source_losusyntax_parser
#define define_source_losusyntax_parser

/* declare sgement */
#define NO_JUMP -1
#define __losuSyntaxParBlock(lex)                                             \
  {                                                                           \
    __losuSyntaxParStatBlock (lex);                                           \
  }

/* code segment */

_inlineScode *
__losu_syntaxParser_parse (LosuVm *vm, _syntaxIO *io)
{
  _syntaxLex lex = { ._syntaxLexIdt = {
                         .nowidt = 0,
                         .read = 0,
                         .size = 4,
                         .tmp = 0,
                     } };
  _syntaxFunc func;

  lex.deepth = 0;
  _l_bool islast = 0;

  __losuSyntaxLexSetin (vm, &lex, io, __losu_objString_new (vm, io->name));
  __losuSyntaxParNewfunc (&lex, &func);
  __losuSyntaxParNext (&lex);
  while (!islast && !__losuSyntaxParCheckBlock (lex.tk.token))
    islast = __losuSyntaxParStat ((_syntaxLex *)(&lex));
  __losuSyntaxParCheckCondtion (&lex, (lex.tk.token != TOKEN_ELSEIF),
                                __config_losucore_errmsg_msgInvalidElif);
  __losuSyntaxParCheckCondtion (&lex, (lex.tk.token != TOKEN_ELSE),
                                __config_losucore_errmsg_msgInvalidElse);
  __losuSyntaxParCheckCondtion (&lex, (lex.tk.token == TOKEN_EOZ),
                                __config_losucore_errmsg_msgMissingEOZ);
  __losuSyntaxParDelfunc (&lex);
  return func.fcode;
}

static void
__losuSyntaxParError (_syntaxLex *lex, int16_t tk)
{
  char t[8];
  __losuSyntaxLexTtS (tk, t);
  __losuSyntaxError (lex, __config_losucore_errmsg_msgParserError, t);
}

static void
__losuSyntaxParNewfunc (_syntaxLex *lex, _syntaxFunc *func)
{
  _inlineScode *f = (_inlineScode *)__losu_objFunc_scodeNew (lex->vm);
  func->prev = lex->fs;
  func->lexer = lex;
  func->vm = lex->vm;
  func->stacklevel = 0;
  func->naloc = 0;
  func->nclosure = 0;
  func->breakl = NULL;
  func->fcode = f;
  func->pc = 0;
  func->lasttarget = 0;
  func->lastline = 0;
  func->jump = NO_JUMP;

  lex->fs = func;

  /* *f = (_inlineScode){ */
  f->src = lex->source;
  f->code = NULL;
  f->maxstacksize = 0;
  f->narg = 0;
  f->isVarg = 0;
  f->marked = 0;
  /* }; */
}

static void
__losuSyntaxParDelfunc (_syntaxLex *lex)
{
  LosuVm *vm = lex->vm;
  _syntaxFunc *func = lex->fs;
  _inlineScode *f = func->fcode;
  __losuSyntaxCgenCodearg0 (func, INS_END);
  __losuSyntaxCgenGetL (func);
  __losuSyntaxParRemovelcvar (lex, func->naloc);
  __losu_mem_reallocvector (vm, f->localvar, f->nlocalvar, _inlineLocalvar);
  __losu_mem_reallocvector (vm, f->code, func->pc, vmInstruction);
  __losu_mem_reallocvector (vm, f->lcstr, f->nlcstr, _inlineString *);
  __losu_mem_reallocvector (vm, f->lcnum, f->nlcnum, _l_number);
  __losu_mem_reallocvector (vm, f->lcscode, f->nlcscode, _inlineScode *);
  __losu_mem_reallocvector (vm, f->lineinfo, f->nlineinfo + 1, int32_t);
  f->lineinfo[f->nlineinfo++] = INT32_MAX;

#define codesize(f)                                                           \
  (sizeof (_inlineScode) + f->nlcnum * sizeof (_l_number)                     \
   + f->nlcstr * sizeof (_inlineString *)                                     \
   + f->nlcscode * sizeof (_inlineScode *)                                    \
   + f->ncode * sizeof (vmInstruction)                                        \
   + f->nlocalvar * sizeof (_inlineLocalvar)                                  \
   + f->nlineinfo * sizeof (int32_t))
  f->ncode = func->pc;
  vm->nblocks += codesize (f);
#undef codesize

  lex->fs = func->prev;
}

static void
__losuSyntaxParCheck (_syntaxLex *lex, int16_t tk)
{
  if (lex->tk.token != tk)
    __losuSyntaxParError (lex, tk);
  __losuSyntaxParNext (lex);
}

static _l_bool
__losuSyntaxParCheckBlock (int16_t tk)
{
  switch (tk)
    {
    case TOKEN_ELSE:
    case TOKEN_ELSEIF:
    case TOKEN_END:
    /* case TOKEN_ENDB: */
    case TOKEN_TO:
    case TOKEN_EOZ:
      return 1;
    default:
      return 0;
    }
}

static void
__losuSyntaxParCheckCondtion (_syntaxLex *lex, _l_bool c, const char *s)
{
  if (!c)
    __losuSyntaxError (lex, s);
}

static void
__losuSyntaxParCheckMatch (_syntaxLex *lex, int16_t l, int16_t r, int32_t line)
{
  if (lex->tk.token != r)
    {
      char tl[8], tr[8];
      __losuSyntaxLexTtS (l, tl);
      __losuSyntaxLexTtS (r, tr);
      __losuSyntaxError (lex, __config_losucore_errmsg_msgCheckMatch, tl, line,
                         tr);
    }
  __losuSyntaxParNext (lex);
}

static _inlineString *
__losuSyntaxParCheckName (_syntaxLex *lex)
{
  _inlineString *ts;
  __losuSyntaxParCheckCondtion (lex, lex->tk.token == TOKEN_NAME,
                                __config_losucore_errmsg_msgCheckName);
  ts = lex->tk.info.s;
  __losuSyntaxParNext (lex);
  return ts;
}

static void
__losuSyntaxParCheckLimit (_syntaxLex *lex, int32_t v, int32_t l,
                           const char *errmsg)
{
  if (v <= l)
    return;
  /*   sprintf ((char *)lex->vm->staticbuff,
    __config_losucore_errmsg_msgCheckLimit, errmsg, l);
    __losuSyntaxError (lex, (const char *)lex->vm->staticbuff); */
  __losuSyntaxError (lex, __config_losucore_errmsg_msgCheckLimit, errmsg, l);
}

static void
__losuSyntaxParNewlcvar (_syntaxLex *lex, _inlineString *name, int16_t i)
{
  _syntaxFunc *func = lex->fs;
  _inlineScode *f = func->fcode;

  /* check limit? */
  __losuSyntaxParCheckLimit (lex, func->naloc + i + 1, vmOl_MaxLocalvar,
                             __config_losucore_errmsg_msgCheckLimitTMlocvar);

  __losu_mem_growvector (lex->vm, f->localvar, f->nlocalvar, 1,
                         _inlineLocalvar, vmIns_MaxA,
                         __config_losucore_errmsg_msgVectorOverflow);
  f->localvar[f->nlocalvar].name = name;
  func->aloc[func->naloc + i] = f->nlocalvar++;
}

static void
__losuSyntaxParRemovelcvar (_syntaxLex *lex, int16_t i)
{
  _syntaxFunc *func = lex->fs;
  while (i--)
    func->fcode->localvar[func->aloc[--(func->naloc)]].endpc = func->pc;
}

static void
__losuSyntaxParNext (_syntaxLex *lex)
{

  lex->lastline = lex->linenumber;
  if (lex->tkahead.token != TOKEN_EOZ)
    {
      lex->tk = lex->tkahead;
      lex->tkahead.token = TOKEN_EOZ;
    }
  else
    lex->tk.token
        = __losuSyntaxLexNext (lex, (_syntaxTkvalue *)(&(lex->tk.info)));
  /* printf ("tk:%d\n", lex->tk.token);
  if (lex->tk.token < 128)
    printf ("\tvalue:%c\n", lex->tk.token); */
}

static _l_bool
__losuSyntaxParStat (_syntaxLex *lex)
{
  int32_t line = lex->linenumber;
  /* printf ("TK:%d\n", lex->tk.token); */
  switch (lex->tk.token)
    {
    case TOKEN_IF:
      {
        lex->deepth++;
        __losuSyntaxParStatIf (lex, line);
        lex->deepth--;
        return 0;
      }
    case TOKEN_WITH:
      {
        lex->deepth++;
        __losuSyntaxParStatWith (lex, line);
        lex->deepth--;
        return 0;
      }
    case TOKEN_BLOCK:
      {
        lex->deepth++;
        __losuSyntaxParNext (lex);
        __losuSyntaxParCheckMatch (lex, TOKEN_BLOCK, ':', line);
        __losuSyntaxParStatBlock (lex);
        __losuSyntaxParCheckMatch (lex, TOKEN_BLOCK, TOKEN_END, line);
        lex->deepth--;
        return 0;
      }
    case TOKEN_FOR:
      {
        lex->deepth++;
        __losuSyntaxParStatFor (lex, line);
        lex->deepth--;
        return 0;
      }
    case TOKEN_LOOP:
      {
        lex->deepth++;
        __losuSyntaxParStatLoop (lex, line);
        lex->deepth--;
        return 0;
      }
    case TOKEN_UNTIL:
      {
        lex->deepth++;
        __losuSyntaxParStatUntil (lex, line);
        lex->deepth--;
        return 0;
      }
    case TOKEN_FUNCTION:
      {
        lex->deepth++;
        __losuSyntaxParStatFunc (lex, line);
        lex->deepth--;
        return 0;
      }
    case TOKEN_VAR:
      {
        __losuSyntaxParStatVar (lex);
        return 0;
      }
    case TOKEN_NAME:
      {
        __losuSyntaxParStatName (lex);
        return 0;
      }
    case TOKEN_RETURN:
      {
        __losuSyntaxParStatReturn (lex);
        return 1;
      }
    case TOKEN_BREAK:
      {
        __losuSyntaxParStatBreak (lex);
        return 1;
      }
    default:
      {
        __losuSyntaxError (lex, __config_losucore_errmsg_msgInvalidExp);
        return 0;
      }
    }
}
static void
__losuSyntaxParStatIf (_syntaxLex *lex, int32_t line)
{

#define condition(lex, v)                                                     \
  {                                                                           \
    __losuSyntaxParSubExp ((lex), (v), -1);                                   \
    __losuSyntaxCgenGoT ((lex)->fs, (v), 0);                                  \
  }

#define then(lex, v)                                                          \
  {                                                                           \
    __losuSyntaxParNext ((lex));                                              \
    condition ((lex), (v));                                                   \
    __losuSyntaxParCheck ((lex), ':');                                        \
    __losuSyntaxParBlock ((lex));                                             \
  }

  _syntaxFunc *func = lex->fs;
  _syntaxExp v;
  int32_t el = NO_JUMP;
  then (lex, &v);
  while (lex->tk.token == TOKEN_END)
    {
      __losuSyntaxParNext (lex);
      if (lex->tk.token == TOKEN_ELSEIF)
        {
          __losuSyntaxCgenConcat (func, &el, __losuSyntaxCgenJump (func));
          __losuSyntaxCgenPalist (func, v.value._bool.f,
                                  __losuSyntaxCgenGetL (func));
          then (lex, &v);
        }
      else if (lex->tk.token == TOKEN_ELSE)
        {
          lex->tkahead.token = __losuSyntaxLexNext (
              lex, (_syntaxTkvalue *)(&(lex->tkahead.info)));
          if (lex->tkahead.token == ':')
            __losuSyntaxParNext (lex);

          __losuSyntaxCgenConcat (func, &el, __losuSyntaxCgenJump (func));
          __losuSyntaxCgenPalist (func, v.value._bool.f,
                                  __losuSyntaxCgenGetL (func));
          __losuSyntaxParNext (lex);
          __losuSyntaxParBlock (lex);
          __losuSyntaxCgenPalist (func, el, __losuSyntaxCgenGetL (func));
          __losuSyntaxParCheckMatch (lex, TOKEN_IF, TOKEN_END, line);
          break;
        }
      else
        {
          __losuSyntaxCgenConcat (func, &el, v.value._bool.f);
          __losuSyntaxCgenPalist (func, el, __losuSyntaxCgenGetL (func));
          break;
        }
    }

    /* while (lex->tk.token == TOKEN_ELSEIF)
      {
        __losuSyntaxCgenConcat (func, &el, __losuSyntaxCgenJump (func));
        __losuSyntaxCgenPalist (func, v.value._bool.f,
                                __losuSyntaxCgenGetL (func));
        then (lex, &v);
      }
    if (lex->tk.token == TOKEN_ELSE)
      {
        lex->tkahead.token = __losuSyntaxLexNext (
            lex, (_syntaxTkvalue *)(&(lex->tkahead.info)));
        if (lex->tkahead.token == ':')
          __losuSyntaxParNext (lex);

        __losuSyntaxCgenConcat (func, &el, __losuSyntaxCgenJump (func));
        __losuSyntaxCgenPalist (func, v.value._bool.f,
                                __losuSyntaxCgenGetL (func));
        __losuSyntaxParNext (lex);
        __losuSyntaxParBlock (lex);
      }
    else
      __losuSyntaxCgenConcat (func, &el, v.value._bool.f);


    __losuSyntaxCgenPalist (func, el, __losuSyntaxCgenGetL (func));
    __losuSyntaxParCheckMatch (lex, TOKEN_IF, TOKEN_END, line);*/

/* undef segment */
#undef condition
#undef then
}
static void
__losuSyntaxParStatWith (_syntaxLex *lex, int32_t line)
{
#define condition(lex, v)                                                     \
  {                                                                           \
    __losuSyntaxParSubExp ((lex), (v), -1);                                   \
    __losuSyntaxCgenGoT ((lex)->fs, (v), 0);                                  \
  }

  _syntaxFunc *func = lex->fs;
  _syntaxExp v;
  int32_t with = __losuSyntaxCgenGetL (func);
  _syntaxBreak br;
  __losuSyntaxParEnterbreak (func, &br);
  __losuSyntaxParNext (lex);
  condition (lex, &v);
  __losuSyntaxParCheck (lex, ':');
  __losuSyntaxParBlock (lex);
  __losuSyntaxCgenPalist (func, __losuSyntaxCgenJump (func), with);
  __losuSyntaxCgenPalist (func, v.value._bool.f, __losuSyntaxCgenGetL (func));
  __losuSyntaxParCheckMatch (lex, TOKEN_WITH, TOKEN_END, line);
  __losuSyntaxParLeavebreak (func, &br);

#undef condition
}
static void
__losuSyntaxParStatBlock (_syntaxLex *lex)
{
  _syntaxFunc *func = lex->fs;
  int naloc = func->naloc;
  _l_bool is = 0;
  while (!is && !__losuSyntaxParCheckBlock (lex->tk.token))
    is = __losuSyntaxParStat (lex);
  __losuSyntaxCgenAdStack (func, func->naloc - naloc);
  __losuSyntaxParRemovelcvar (lex, func->naloc - naloc);
}
static void
__losuSyntaxParStatFor (_syntaxLex *lex, int32_t line)
{
  _syntaxFunc *func = lex->fs;
  _inlineString *name;
  _syntaxBreak br;
  __losuSyntaxParEnterbreak (func, &br);
  __losuSyntaxParNext (lex);
  name = __losuSyntaxParCheckName (lex);
  switch (lex->tk.token)
    {
    case '=':
    case TOKEN_TO:
      {
        __losuSyntaxParStatForNum (lex, name);
        break;
      }
    case ',':
      {
        __losuSyntaxParStatForObj (lex, name);
        break;
      }
    default:
      __losuSyntaxError (lex, __config_losucore_errmsg_msgInvalidForExp);
    }
  __losuSyntaxParCheckMatch (lex, TOKEN_FOR, TOKEN_END, line);
  __losuSyntaxParLeavebreak (func, &br);
}
static void
__losuSyntaxParStatLoop (_syntaxLex *lex, int32_t line)
{
#define condition(lex, v)                                                     \
  {                                                                           \
    __losuSyntaxParSubExp ((lex), (v), -1);                                   \
    __losuSyntaxCgenGoT ((lex)->fs, (v), 0);                                  \
  }

  _syntaxFunc *func = lex->fs;
  int32_t loop = __losuSyntaxCgenGetL (func);
  _syntaxExp v;
  _syntaxBreak br;
  __losuSyntaxParEnterbreak (func, &br);
  __losuSyntaxParNext (lex);
  __losuSyntaxParBlock (lex);
  __losuSyntaxParCheckMatch (lex, TOKEN_LOOP, TOKEN_TO, line);
  condition (lex, &v);
  __losuSyntaxCgenPalist (func, v.value._bool.f, loop);
  __losuSyntaxParLeavebreak (func, &br);

#undef condition
}
static void
__losuSyntaxParStatUntil (_syntaxLex *lex, int32_t line)
{
#define condition(lex, v)                                                     \
  {                                                                           \
    __losuSyntaxParSubExp ((lex), (v), -1);                                   \
    __losuSyntaxCgenGoF ((lex)->fs, (v), 0);                                  \
  }

  _syntaxFunc *func = lex->fs;
  _syntaxExp v;
  int32_t unt = __losuSyntaxCgenGetL (func);
  _syntaxBreak br;
  __losuSyntaxParEnterbreak (func, &br);
  __losuSyntaxParNext (lex);
  condition (lex, &v);
  __losuSyntaxParCheck (lex, ':');
  __losuSyntaxParBlock (lex);
  __losuSyntaxCgenPalist (func, __losuSyntaxCgenJump (func), unt);
  __losuSyntaxCgenPalist (func, v.value._bool.t, __losuSyntaxCgenGetL (func));
  __losuSyntaxParCheckMatch (lex, TOKEN_UNTIL, TOKEN_END, line);
  __losuSyntaxParLeavebreak (func, &br);

#undef condition
}
static void
__losuSyntaxParStatFunc (_syntaxLex *lex, int32_t line)
{
  _syntaxExp v;
  __losuSyntaxParNext (lex);
  __losuSyntaxParStatFuncBody (lex, __losuSyntaxParStatFuncName (lex, &v),
                               line);
  __losuSyntaxCgenSetVar (lex, &v);
}
static void
__losuSyntaxParStatVar (_syntaxLex *lex)
{
#define isSet(lex, c)                                                         \
  ((lex->tk.token == c) ? (__losuSyntaxParNext (lex), 1) : 0)

  if (lex->deepth == 0) /* global */
    {
      __losuSyntaxParNext (lex);
      __losuSyntaxParStatName (lex);
      return;
    }
  int32_t nv = 0, ne = 0;
  do
    {
      __losuSyntaxParNext (lex);
      __losuSyntaxParNewlcvar (lex, __losuSyntaxParCheckName (lex), nv++);
    }
  while (lex->tk.token == ',');
  if (isSet (lex, '='))
    ne = __losuSyntaxParExplist (lex);
  else
    ne = 0;
  __losuSyntaxParAdStack (lex, nv, ne);
  __losuSyntaxParAdLcvar (lex, nv);

#undef isSet
}
static void
__losuSyntaxParStatName (_syntaxLex *lex)
{
  _syntaxFunc *func = lex->fs;
  _syntaxExp v;
  __losuSyntaxParVarFunc (lex, &v);
  if (v.type == VE)
    {
      __losuSyntaxParCheckCondtion (lex, __losuSyntaxCgenIsopen (func),
                                    __config_losucore_errmsg_msgInvalidExp);
      __losuSyntaxCgenSetNcallr (func, 0);
    }
  else
    __losuSyntaxCgenAdStack (func,
                             __losuSyntaxParStatNameAssment (lex, &v, 1));
}
static void
__losuSyntaxParStatReturn (_syntaxLex *lex)
{
  _syntaxFunc *func = lex->fs;
  __losuSyntaxParNext (lex);
  if (!__losuSyntaxParCheckBlock (lex->tk.token))
    __losuSyntaxParExplist (lex);
  __losuSyntaxCgenCodearg1 (func, INS_RETURN, lex->fs->naloc);
  func->stacklevel = func->naloc;
}
static void
__losuSyntaxParStatBreak (_syntaxLex *lex)
{
  _syntaxFunc *func = lex->fs;
  _syntaxBreak *br = func->breakl;
  int32_t c = func->stacklevel;
  __losuSyntaxParNext (lex);
  if (br) /* break lable is exsist  */
    {
      __losuSyntaxCgenAdStack (func, c - br->stacklevel);
      __losuSyntaxCgenConcat (func, &br->breaklist,
                              __losuSyntaxCgenJump (func));
      __losuSyntaxCgenAdStack (func, br->stacklevel - c);
    }
}

static void
__losuSyntaxParEnterbreak (_syntaxFunc *func, _syntaxBreak *br)
{
  br->stacklevel = func->stacklevel;
  br->breaklist = NO_JUMP;
  br->pre = func->breakl;
  func->breakl = br;
}
static void
__losuSyntaxParLeavebreak (_syntaxFunc *func, _syntaxBreak *br)
{
  func->breakl = br->pre;
  __losuSyntaxCgenPalist (func, br->breaklist, __losuSyntaxCgenGetL (func));
}

static void
__losuSyntaxParStatForNum (_syntaxLex *lex, _inlineString *vname)
{
  /*   __losuSyntaxParCheck (lex, TOKEN_TO); */
  __losuSyntaxParNext (lex);
  __losuSyntaxParExp (lex);
  __losuSyntaxParCheck (lex, ',');
  __losuSyntaxParExp (lex);
  if (lex->tk.token == ',') /* step */
    {
      __losuSyntaxParNext (lex);
      __losuSyntaxParExp (lex);
    }
  else
    __losuSyntaxCgenNumber (lex->fs, 1);

  __losuSyntaxParNewlcvar (lex, vname, 0);
  __losuSyntaxParNewlcvar (lex, __losu_objString_newconst (lex->vm, "__MAX__"),
                           1);
  __losuSyntaxParNewlcvar (lex,
                           __losu_objString_newconst (lex->vm, "__STEP__"), 2);

  __losuSyntaxParStatForBody (lex, 0);
}
static void
__losuSyntaxParStatForObj (_syntaxLex *lex, _inlineString *idx)
{
  _inlineString *val;
  __losuSyntaxParNext (lex);
  val = __losuSyntaxParCheckName (lex);
  __losuSyntaxParCheckCondtion (
      lex,
      (lex->tk.token == TOKEN_NAME && !strcmp (lex->tk.info.s->str, "in")),
      __config_losucore_errmsg_msgInvalidForExp);
  __losuSyntaxParNext (lex);
  __losuSyntaxParExp (lex);

  __losuSyntaxParNewlcvar (lex,
                           __losu_objString_newconst (lex->vm, "__THIS__"), 0);
  __losuSyntaxParNewlcvar (lex, idx, 1);
  __losuSyntaxParNewlcvar (lex, val, 2);
  __losuSyntaxParStatForBody (lex, 1);
}
static void
__losuSyntaxParStatForBody (_syntaxLex *lex, _l_bool isO)
{
  struct
  {
    vmIns_OP pre;
    vmIns_OP loop;
  } const _inline_ins[] = {
    { INS_FORPREP, INS_FORLOOP },
    { INS_LFORPREP, INS_LFORLOOP },
  };

  _syntaxFunc *func = lex->fs;
  int32_t prep
      = __losuSyntaxCgenCodearg1 (func, _inline_ins[isO].pre, NO_JUMP);
  int32_t block = __losuSyntaxCgenGetL (func);
  __losuSyntaxParCheck (lex, ':');
  __losuSyntaxParAdLcvar (lex, 3);
  __losuSyntaxParBlock (lex);
  __losuSyntaxCgenPalist (
      func, __losuSyntaxCgenCodearg1 (func, _inline_ins[isO].loop, NO_JUMP),
      block);
  __losuSyntaxCgenPalist (func, prep, __losuSyntaxCgenGetL (func));
  __losuSyntaxParRemovelcvar (lex, 3);
}

static _l_bool
__losuSyntaxParStatFuncName (_syntaxLex *lex, _syntaxExp *v)
{
  _l_bool i = 0;
  __losuSyntaxParSvar (lex, __losuSyntaxParCheckName (lex), v);
  while (lex->tk.token == '.')
    {
      __losuSyntaxParNext (lex);
      __losuSyntaxCgenTostack (lex, v, 1);
      __losuSyntaxCgenCodearg1 (
          lex->fs, INS_PUSHSTRING,
          __losuSyntaxParStrconst (lex->fs, __losuSyntaxParCheckName (lex)));
      v->type = VI;
      i = 1;
    }
  return i;
}
static void
__losuSyntaxParStatFuncBody (_syntaxLex *lex, _l_bool nself, int32_t line)
{

  _syntaxFunc nfs;

  __losuSyntaxParNewfunc (lex, &nfs);
  nfs.fcode->defedline = line;
  __losuSyntaxParCheck (lex, '(');
  if (nself)
    {
      __losuSyntaxParNewlcvar (lex,
                               __losu_objString_newconst (lex->vm, "self"), 0);
      __losuSyntaxParAdLcvar (lex, 1);
    }
  __losuSyntaxParStatFuncParlist (lex);
  __losuSyntaxParCheck (lex, ')');
  __losuSyntaxParCheck (lex, ':');

  while (!__losuSyntaxParCheckBlock (lex->tk.token))
    if (__losuSyntaxParStat (lex))
      break;
  __losuSyntaxParCheckMatch (lex, TOKEN_FUNCTION, TOKEN_END, line);
  __losuSyntaxParDelfunc (lex);

  /* push func */
  _syntaxFunc *func = lex->fs;
  _inlineScode *f = func->fcode;
  for (int32_t i = 0; i < nfs.nclosure; i++)
    __losuSyntaxCgenTostack (lex, &(nfs.closure[i]), 1);
  __losu_mem_growvector (lex->vm, f->lcscode, f->nlcscode, 1, _inlineScode *,
                         vmIns_MaxA,
                         __config_losucore_errmsg_msgVectorOverflow);
  f->lcscode[f->nlcscode++] = nfs.fcode;
  __losuSyntaxCgenCodearg2 (func, INS_PUSHFUNCTION, f->nlcscode - 1,
                            nfs.nclosure);
}
static void
__losuSyntaxParStatFuncParlist (_syntaxLex *lex)
{
#define option(lex)                                                           \
  ((lex->tk.token == ',') ? (__losuSyntaxParNext (lex), 1) : 0)

  _l_bool isV = 0;
  int32_t np = 0;
  _syntaxFunc *func = lex->fs;
  if (lex->tk.token != ')')
    {
      do
        {
          switch (lex->tk.token)
            {
            case TOKEN_ARG:
              {
                __losuSyntaxParNext (lex);
                isV = 1;
                break;
              }
            case TOKEN_NAME:
              {
                __losuSyntaxParNewlcvar (lex, __losuSyntaxParCheckName (lex),
                                         np++);
                break;
              }
            default:
              {
                __losuSyntaxError (lex, __config_losucore_errmsg_msgCheckName);
              }
            }
        }
      while (option (lex));
    }
  __losuSyntaxParAdLcvar (lex, np);
  func->fcode->narg = func->naloc;
  func->fcode->isVarg = isV;
  if (isV)
    {
      __losuSyntaxParNewlcvar (lex, __losu_objString_newconst (lex->vm, "arg"),
                               0);
      __losuSyntaxParAdLcvar (lex, 1);
    }
  __losuSyntaxCgenDtStack (func, func->naloc);

#undef option
}

static int32_t
__losuSyntaxParStatNameAssment (_syntaxLex *lex, _syntaxExp *v, int32_t nvar)
{
  int32_t left = 0;
  if (lex->tk.token == ',')
    {
      _syntaxExp nv;
      __losuSyntaxParNext (lex);
      __losuSyntaxParVarFunc (lex, &nv);
      __losuSyntaxParCheckCondtion (lex, (nv.type != VE),
                                    __config_losucore_errmsg_msgInvalidExp);
      left = __losuSyntaxParStatNameAssment (lex, &nv, nvar + 1);
    }
  else
    {
      int32_t nexp = 0;
      if (lex->tk.token == '=')
        {
          __losuSyntaxParNext (lex);
          nexp = __losuSyntaxParExplist (lex);
        }
      __losuSyntaxParAdStack (lex, nvar, nexp);
    }
  if (v->type != VI)
    __losuSyntaxCgenSetVar (lex, v);
  else
    {
      __losuSyntaxCgenCodearg2 (lex->fs, INS_SETUNIT, left + nvar + 2, 1);
      left += 2;
    }
  return left;
}

static int32_t
__losuSyntaxParExplist (_syntaxLex *lex)
{
  int32_t n = 1;
  _syntaxExp v;
  __losuSyntaxParSubExp (lex, &v, -1);
  while (lex->tk.token == ',')
    {
      __losuSyntaxCgenTostack (lex, &v, 1);
      __losuSyntaxParNext (lex);
      __losuSyntaxParSubExp (lex, &v, -1);
      n++;
    }
  __losuSyntaxCgenTostack (lex, &v, 0);
  return n;
}
static void
__losuSyntaxParAdStack (_syntaxLex *lex, int32_t nv, int32_t ne)
{
  _syntaxFunc *func = lex->fs;
  int32_t d = ne - nv;
  if (ne > 0 && __losuSyntaxCgenIsopen (func))
    {
      d--;
      if (d <= 0)
        {
          __losuSyntaxCgenSetNcallr (func, -d);
          d = 0;
        }
      else
        __losuSyntaxCgenSetNcallr (func, 0);
    }
  __losuSyntaxCgenAdStack (func, d);
}
static void
__losuSyntaxParAdLcvar (_syntaxLex *lex, int32_t nv)
{
  while (nv--)
    lex->fs->fcode->localvar[lex->fs->aloc[lex->fs->naloc++]].startpc
        = lex->fs->pc;
}
static void
__losuSyntaxParVarFunc (_syntaxLex *lex, _syntaxExp *v)
{
#define lookahead(lex)                                                        \
  {                                                                           \
    (lex)->tkahead.token = __losuSyntaxLexNext (                              \
        lex, (_syntaxTkvalue *)(&((lex)->tkahead.info)));                     \
  }

  __losuSyntaxParSvar (lex, __losuSyntaxParCheckName (lex), v);
  while (1)
    {
      switch (lex->tk.token)
        {
        case '.':
          {
            __losuSyntaxParNext (lex);
            lookahead (lex);
            switch (lex->tkahead.token)
              {
              case '(':
              case '{':
              case TOKEN_STRING:
                {
                  int32_t name = __losuSyntaxParStrconst (
                      lex->fs, __losuSyntaxParCheckName (lex));
                  __losuSyntaxCgenTostack (lex, v, 1);
                  __losuSyntaxCgenCodearg1 (lex->fs, INS_PUSHSELF, name);
                  __losuSyntaxParExpFargs (lex, 1);
                  v->type = VE;
                  v->value._bool.t = v->value._bool.f = NO_JUMP;
                  break;
                }
              default:
                {
                  __losuSyntaxCgenTostack (lex, v, 1);
                  __losuSyntaxCgenCodearg1 (
                      lex->fs, INS_PUSHSTRING,
                      __losuSyntaxParStrconst (
                          lex->fs, __losuSyntaxParCheckName (lex)));
                  v->type = VI;
                  break;
                }
              }
            break;
          }
        case '[':
          {
            __losuSyntaxParNext (lex);
            __losuSyntaxCgenTostack (lex, v, 1);
            v->type = VI;
            __losuSyntaxParExp (lex);
            __losuSyntaxParCheck (lex, ']');
            break;
          }
        case '(':
        case TOKEN_STRING:
        case '{':
          {
            __losuSyntaxCgenTostack (lex, v, 1);
            __losuSyntaxParExpFargs (lex, 0);
            v->type = VE;
            v->value._bool.f = v->value._bool.t = NO_JUMP;
            break;
          }
        default:
          return;
        }
    }

#undef lookahead
}

static void
__losuSyntaxParExp (_syntaxLex *lex)
{
  _syntaxExp v;
  __losuSyntaxParSubExp (lex, &v, -1);
  __losuSyntaxCgenTostack (lex, &v, 1);
}
static int32_t
__losuSyntaxParExpVarlevel (_syntaxLex *lex, _inlineString *n, _syntaxExp *v)
{
  _syntaxFunc *func;
  int32_t lev = 0;
  for (func = lex->fs; func; func = func->prev)
    {
      for (int32_t i = func->naloc - 1; i >= 0; i--)
        {
          if (n == func->fcode->localvar[func->aloc[i]].name)
            {
              v->type = VL;
              v->value.index = i;
              return lev;
            }
        }
      lev++;
    }
  v->type = VG;
  return -1;
}

static void
__losuSyntaxParSvar (_syntaxLex *lex, _inlineString *n, _syntaxExp *var)
{
  int32_t l = __losuSyntaxParExpVarlevel (lex, n, var);
  if (l >= 1)
    {
      { /* push closure */
        _syntaxFunc *func = lex->fs;
        _syntaxExp v;
        int32_t l = __losuSyntaxParExpVarlevel (lex, n, &v);
        if (l == -1)
          v.value.index = __losuSyntaxParStrconst (func->prev, n);
        else if (l != 1)
          __losuSyntaxError (lex, __config_losucore_errmsg_msgInvalidClosure,
                             n->str);

        /* index closure */
        int16_t c = -1;
        for (int16_t i = 0; i < func->nclosure; i++)
          if (func->closure[i].type == v.type
              && func->closure[i].value.index == v.value.index)
            {
              c = i;
              break;
            }
        if (c < 0)
          {
            func->closure[func->nclosure] = v;
            c = func->nclosure++;
          }
        __losuSyntaxCgenCodearg1 (func, INS_PUSHUPVALUE, c);
      }
      var->type = VE;
      var->value._bool.t = var->value._bool.f = NO_JUMP;
    }
  else if (l == -1)
    var->value.index = __losuSyntaxParStrconst (lex->fs, n);
}
static int32_t
__losuSyntaxParStrconst (_syntaxFunc *func, _inlineString *s)
{
  _inlineScode *f = func->fcode;
  int32_t c = s->cstidx;
  if (c >= f->nlcstr || f->lcstr[c] != s)
    {
      __losu_mem_growvector (func->vm, f->lcstr, f->nlcstr, 1, _inlineString *,
                             vmIns_MaxU,
                             __config_losucore_errmsg_msgVectorOverflow);
      c = f->nlcstr++;
      s->cstidx = c;
      f->lcstr[c] = s;
    }
  return c;
}

static int32_t
__losuSyntaxParSubExp (_syntaxLex *lex, _syntaxExp *v, int l)
{
#define getunop(v, op)                                                        \
  {                                                                           \
    switch (op)                                                               \
      {                                                                       \
      case TOKEN_NOT:                                                         \
        v = INS_UNOP_NOT;                                                     \
        break;                                                                \
      case '-':                                                               \
        v = INS_UNOP_NEG;                                                     \
        break;                                                                \
      default:                                                                \
        v = INS_UNOP_NULL;                                                    \
        break;                                                                \
      }                                                                       \
  }

#define getbinop(v, op)                                                       \
  {                                                                           \
    switch (op)                                                               \
      {                                                                       \
      case '+':                                                               \
        v = INS_BINOP_ADD;                                                    \
        break;                                                                \
      case '-':                                                               \
        v = INS_BINOP_SUB;                                                    \
        break;                                                                \
      case '*':                                                               \
        v = INS_BINOP_MULT;                                                   \
        break;                                                                \
      case '/':                                                               \
        v = INS_BINOP_DIV;                                                    \
        break;                                                                \
      case '^':                                                               \
        v = INS_BINOP_POW;                                                    \
        break;                                                                \
      case TOKEN_CONCAT:                                                      \
        v = INS_BINOP_CONCAT;                                                 \
        break;                                                                \
      case TOKEN_EQ:                                                          \
        v = INS_BINOP_EQ;                                                     \
        break;                                                                \
      case TOKEN_NE:                                                          \
        v = INS_BINOP_NE;                                                     \
        break;                                                                \
      case '<':                                                               \
        v = INS_BINOP_LT;                                                     \
        break;                                                                \
      case TOKEN_LE:                                                          \
        v = INS_BINOP_LE;                                                     \
        break;                                                                \
      case '>':                                                               \
        v = INS_BINOP_GT;                                                     \
        break;                                                                \
      case TOKEN_GE:                                                          \
        v = INS_BINOP_GE;                                                     \
        break;                                                                \
      case TOKEN_AND:                                                         \
        v = INS_BINOP_AND;                                                    \
        break;                                                                \
      case TOKEN_OR:                                                          \
        v = INS_BINOP_OR;                                                     \
        break;                                                                \
      default:                                                                \
        v = INS_BINOP_NULL;                                                   \
        break;                                                                \
      }                                                                       \
  }

  struct
  {
    char left;
    char right;
  } const priority[] = {
    { 5, 5 }, /* + */
    { 5, 5 }, /* - */
    { 6, 6 }, /* * */
    { 6, 6 }, /* / */
    { 9, 8 }, /* ^ */
    { 4, 3 }, /* & */

    { 2, 2 }, /* != */
    { 2, 2 }, /* == */

    { 2, 2 }, /* < */
    { 2, 2 }, /* <= */
    { 2, 2 }, /* > */
    { 2, 2 }, /* >= */

    { 1, 1 }, /* and */
    { 1, 1 }, /* or */
  };

  int op, uop;
  getunop (uop, lex->tk.token);
  if (uop != INS_UNOP_NULL)
    {
      __losuSyntaxParNext (lex);
      __losuSyntaxParSubExp (lex, v, 7);
      __losuSyntaxCgenPrefix (lex, uop, v);
    }
  else
    __losuSyntaxParSimpleExp (lex, v);

  getbinop (op, lex->tk.token);
  /* printf ("\top:%d\n", op); */
  while (op != INS_BINOP_NULL && priority[op].left > l)
    {
      _syntaxExp v2;
      int l2;
      __losuSyntaxParNext (lex);
      __losuSyntaxCgenInfix (lex, op, v);
      l2 = __losuSyntaxParSubExp (lex, &v2, priority[op].right);
      __losuSyntaxCgenPosfix (lex, op, v, &v2);
      op = l2;
    }
  return op;

#undef getunop
#undef getbinop
}
static void
__losuSyntaxParExpFargs (_syntaxLex *lex, _l_bool slf)
{
  _syntaxFunc *func = lex->fs;
  int sl = func->stacklevel - slf - 1;
  int line = lex->linenumber;
  switch (lex->tk.token)
    {
    case '(':
      {
        __losuSyntaxParNext (lex);
        if (lex->tk.token != ')')
          __losuSyntaxParExplist (lex);
        __losuSyntaxParCheckMatch (lex, '(', ')', line);
        break;
      }
    case '{':
      {
        __losuSyntaxParUnitConstructor (lex);
        break;
      }
    case TOKEN_STRING:
      {
        __losuSyntaxCgenCodearg1 (
            lex->fs, INS_PUSHSTRING,
            __losuSyntaxParStrconst (lex->fs, lex->tk.info.s));
        __losuSyntaxParNext (lex);
        break;
      }
    default:
      {
        __losuSyntaxError (lex, __config_losucore_errmsg_msgExpectedFarg);
        break;
      }
    }
  func->stacklevel = sl;
  __losuSyntaxCgenCodearg2 (func, INS_CALL, sl, 255);
}

static void
__losuSyntaxParSimpleExp (_syntaxLex *lex, _syntaxExp *v)
{
  _syntaxFunc *func = lex->fs;
  switch (lex->tk.token)
    {
    case TOKEN_NUMBER:
      {
        _l_number n = lex->tk.info.num;
        __losuSyntaxParNext (lex);
        __losuSyntaxCgenNumber (func, n);
        break;
      }
    case TOKEN_STRING:
      {
        __losuSyntaxCgenCodearg1 (
            lex->fs, INS_PUSHSTRING,
            __losuSyntaxParStrconst (lex->fs, lex->tk.info.s));
        __losuSyntaxParNext (lex);
        break;
      }
    case TOKEN_NULL:
      {
        __losuSyntaxCgenAdStack (func, -1);
        __losuSyntaxParNext (lex);
        break;
      }
    case TOKEN_FUNCTION:
      {
        lex->deepth++;
        __losuSyntaxParNext (lex);
        __losuSyntaxParStatFuncBody (lex, 0, lex->linenumber);
        lex->deepth--;
        break;
      }
    case TOKEN_NAME:
      {
        __losuSyntaxParVarFunc (lex, v);
        return;
      }
    case '{':
      {
        __losuSyntaxParUnitConstructor (lex);
        break;
      }
    case '(':
      {
        __losuSyntaxParNext (lex);
        __losuSyntaxParSubExp (lex, v, -1);
        __losuSyntaxParCheck (lex, ')');
        return;
      }
    default:
      {
        __losuSyntaxError (lex, __config_losucore_errmsg_msgInvalidExp);
        return;
      }
    }
  v->type = VE;
  v->value._bool.t = v->value._bool.f = NO_JUMP;
}
static void
__losuSyntaxParUnitConstructor (_syntaxLex *lex)
{
  _syntaxFunc *func = lex->fs;
  int32_t line = lex->linenumber;
  int32_t pc = __losuSyntaxCgenCodearg1 (func, INS_CREATEUNIT, 0);
  int32_t niss;
  __losuSyntaxParCheck (lex, '{');
  switch (lex->tk.token)
    {
    case '}':
      {
        niss = 0;
        break;
      }
    case TOKEN_NAME:
      {
        lex->tkahead.token = __losuSyntaxLexNext (
            lex, (_syntaxTkvalue *)(&(lex->tkahead.info)));
        if (lex->tkahead.token == ',')
          goto case_default;
        niss = __losuSyntaxParUnitMapfield (lex);
        break;
      }
    case '[':
      {
        niss = __losuSyntaxParUnitMapfield (lex);
        break;
      }
    default:
      {
      case_default:
        niss = __losuSyntaxParUnitListfield (lex);
        break;
      }
    }
  __losuSyntaxParCheckMatch (lex, '{', '}', line);
  cgIns_SetU (func->fcode->code[pc], niss);
}

static int32_t
__losuSyntaxParUnitMapfield (_syntaxLex *lex)
{
  _syntaxFunc *func = lex->fs;
  int32_t n = 1;
  switch (lex->tk.token)
    {
    case TOKEN_NAME:
      {
        __losuSyntaxCgenCodearg1 (
            lex->fs, INS_PUSHSTRING,
            __losuSyntaxParStrconst (lex->fs, __losuSyntaxParCheckName (lex)));
        break;
      }
    case '[':
      {
        __losuSyntaxParNext (lex);
        __losuSyntaxParExp (lex);
        __losuSyntaxParCheck (lex, ']');
        break;
      }
    default:
      {
        __losuSyntaxError (lex, __config_losucore_errmsg_msgCheckName);
      }
    }

  __losuSyntaxParCheck (lex, ':');
  /* __losuSyntaxParNext (lex); */

  __losuSyntaxParExp (lex);

  while (lex->tk.token == ',')
    {
      __losuSyntaxParNext (lex);
      if (lex->tk.token == '}')
        break;
      switch (lex->tk.token)
        {
        case TOKEN_NAME:
          {
            __losuSyntaxCgenCodearg1 (
                lex->fs, INS_PUSHSTRING,
                __losuSyntaxParStrconst (lex->fs,
                                         __losuSyntaxParCheckName (lex)));
            break;
          }
        case '[':
          {
            __losuSyntaxParNext (lex);
            __losuSyntaxParExp (lex);
            __losuSyntaxParCheck (lex, ']');
            break;
          }
        default:
          {
            __losuSyntaxError (lex, __config_losucore_errmsg_msgCheckName);
          }
        }
      __losuSyntaxParCheck (lex, ':');
      /* __losuSyntaxParNext (lex); */

      __losuSyntaxParExp (lex);
      n++;
      if (n % vmOl_MaxSetmap == 0)
        __losuSyntaxCgenCodearg1 (func, INS_SETMAP, vmOl_MaxSetmap);
    }
  __losuSyntaxCgenCodearg1 (func, INS_SETMAP, n % vmOl_MaxSetmap);
  return n;
}
static int32_t
__losuSyntaxParUnitListfield (_syntaxLex *lex)
{
  _syntaxFunc *func = lex->fs;
  int32_t n = 1;
  __losuSyntaxParExp (lex);
  while (lex->tk.token == ',')
    {
      __losuSyntaxParNext (lex);
      if (lex->tk.token == '}')
        break;
      __losuSyntaxParExp (lex);
      n++;
      if (n % vmOl_MaxSetlist == 0)
        __losuSyntaxCgenCodearg2 (func, INS_SETLIST, n / vmOl_MaxSetlist - 1,
                                  vmOl_MaxSetlist);
    }
  __losuSyntaxCgenCodearg2 (func, INS_SETLIST, n / vmOl_MaxSetlist,
                            n % vmOl_MaxSetlist);
  return n;
}

#undef NO_JUMP
#undef __losuSyntaxParBlock
#endif /* define_source_losusyntax_parser */

#ifndef define_source_losusyntax_codegen
#define define_source_losusyntax_codegen
#define NO_JUMP -1

static const struct
{
  vmIns_OP op;
  int arg;
} _alops[] = { { INS_ADD, 0 },         { INS_SUB, 0 },
               { INS_MULT, 0 },        { INS_DIV, 0 },
               { INS_POW, 0 },         { INS_CONCAT, 0 },
               { INS_JMPNE, NO_JUMP }, { INS_JMPEQ, NO_JUMP },
               { INS_JMPLT, NO_JUMP }, { INS_JMPLE, NO_JUMP },
               { INS_JMPGT, NO_JUMP }, { INS_JMPGE, NO_JUMP } };

#define iO INS_MODE_OP
#define iBA INS_MODE_IBA
#define iU INS_MODE_IU
#define iS INS_MODE_IS
#define V 0 /* V means variable */
static const struct
{
  vmIns_Mode op;
  int8_t push;
  int8_t pop;
} _vmops[] = {
  { iO, 0, 0 }, /* INS_END */
  { iU, 0, 0 }, /* INS_RETURN */

  { iBA, 0, 0 }, /* INS_CALL */

  { iU, V, 0 }, /* INS_PUSHNULL */
  { iU, V, 0 }, /* INS_POP */

  { iU, 1, 0 },  /* INS_PUSHSTRING */
  { iU, 1, 0 },  /* INS_PUSHNUM */
  { iU, 1, 0 },  /* INS_PUSHUPVALUE */
  { iBA, V, 0 }, /* INS_PUSHFUNCTION */
  { iU, 2, 1 },  /* INS_PUSHSELF */

  { iU, 1, 0 }, /* INS_GETLOCAL */
  { iU, 1, 0 }, /* INS_GETGLOBAL */
  { iU, 0, 1 }, /* INS_SETLOCAL */
  { iU, 0, 1 }, /* INS_SETGLOBAL */

  { iU, 1, 0 },  /* INS_CREATEUNIT */
  { iBA, V, 0 }, /* INS_SETUNIT */
  { iO, 1, 2 },  /* INS_GETUNIT */
  { iBA, V, 0 }, /* INS_SETLIST */
  { iU, V, 0 },  /* INS_SETMAP */

  { iO, 1, 2 }, /* INS_ADD */
  { iO, 1, 2 }, /* INS_SUB */
  { iO, 1, 2 }, /* INS_MULT */
  { iO, 1, 2 }, /* INS_DIV */
  { iO, 1, 2 }, /* INS_POW */
  { iO, 1, 2 }, /* INS_CONCAT */
  { iO, 1, 1 }, /* INS_MINUS */
  { iO, 1, 1 }, /* INS_NOT */

  { iS, 0, 2 }, /* INS_JMPNE */
  { iS, 0, 2 }, /* INS_JMPEQ */
  { iS, 0, 2 }, /* INS_JMPLT */
  { iS, 0, 2 }, /* INS_JMPLE */
  { iS, 0, 2 }, /* INS_JMPGT */
  { iS, 0, 2 }, /* INS_JMPGE */

  { iS, 0, 1 }, /* INS_JMPT */
  { iS, 0, 1 }, /* INS_JMPF */
  { iS, 0, 1 }, /* INS_JMPONT */
  { iS, 0, 1 }, /* INS_JMPONF */
  { iS, 0, 0 }, /* INS_JMP */
  { iO, 0, 0 }, /* INS_PUSHNULLJMP */

  { iS, 0, 0 }, /* INS_FORPREP */
  { iS, 0, 3 }, /* INS_FORLOOP */
  { iS, 2, 0 }, /* INS_LFORPREP */
  { iS, 0, 3 }, /* INS_LFORLOOP */

};

#undef iO
#undef iBA
#undef iU
#undef iS
#undef V

static int32_t
__losuSyntaxCgenCodearg (_syntaxFunc *func, vmIns_OP o, int32_t arg1,
                         int32_t arg2)
{
  _syntaxLex *lex = func->lexer;
  _inlineScode *f = func->fcode;
  vmInstruction i = func->pc > func->lasttarget
                        ? func->fcode->code[func->pc - 1]
                        : ((vmInstruction)INS_END);
  int32_t dt = _vmops[o].push - _vmops[o].pop;
  _l_bool optd = 0;

  switch (o)
    {
    case INS_PUSHFUNCTION: /* V */
      {
        dt = -arg2 + 1;
        break;
      }
    case INS_SETUNIT:
      {
        dt = -arg2;
        break;
      }
    case INS_SETLIST:
      {
        if (arg2 == 0)
          return NO_JUMP;
        dt = -arg2;
        break;
      }
    case INS_SETMAP:
      {
        if (arg1 == 0)
          return NO_JUMP;
        dt = -2 * arg1;
        break;
      }
    case INS_PUSHNULL:
      {
        if (arg1 == 0)
          return NO_JUMP;
        dt = arg1;
        switch (cgIns_GetOp (i))
          {
          case INS_PUSHNULL:
            cgIns_SetU (i, cgIns_GetU (i) + arg1);
            optd = 1;
            break;
          default:
            break;
          }
        break;
      }
    case INS_POP: /* V */
      {
        if (arg1 == 0)
          return NO_JUMP;
        dt = -arg1;
        switch (cgIns_GetOp (i))
          {
          case INS_SETUNIT:
            {
              cgIns_SetB (i, cgIns_GetB (i) + arg1);
              optd = 1;
              break;
            }
          default:
            break;
          }
        break;
      }
    case INS_JMPNE:
      {
        if (i == cgIns_NewU (INS_PUSHNULL, 1))
          {
            i = cgIns_NewS (INS_JMPT, NO_JUMP);
            optd = 1;
          }
        break;
      }
    case INS_JMPEQ:
      {
        if (i == cgIns_NewU (INS_PUSHNULL, 1))
          {
            i = cgIns_NewOp (INS_NOT);
            dt = -1;
            optd = 1;
          }
        break;
      }
    case INS_JMPT:
    case INS_JMPONT:
      {
        switch (cgIns_GetOp (i))
          {
          case INS_NOT:
            {
              i = cgIns_NewS (INS_JMPF, NO_JUMP);
              optd = 1;
              break;
            }
          case INS_PUSHNULL:
            {
              if (cgIns_GetU (i) == 1)
                {
                  func->pc--;
                  __losuSyntaxCgenDtStack (func, -1);
                  return NO_JUMP;
                }
              break;
            }
          default:
            break;
          }
        break;
      }
    case INS_JMPF:
    case INS_JMPONF:
      {
        switch (cgIns_GetOp (i))
          {
          case INS_NOT:
            {
              i = cgIns_NewS (INS_JMPT, NO_JUMP);
              optd = 1;
              break;
            }
          case INS_PUSHNULL:
            {
              if (cgIns_GetU (i) == 1)
                {
                  i = cgIns_NewS (INS_JMP, NO_JUMP);
                  optd = 1;
                }
              break;
            }
          default:
            break;
          }
        break;
      }
    default:
      break;
    }

  __losuSyntaxCgenDtStack (func, dt);
  if (optd)
    {
      func->fcode->code[func->pc - 1] = i;
      return func->pc - 1;
    }
  switch (_vmops[o].op)
    {
    case INS_MODE_OP:
      {
        i = cgIns_NewOp (o);
        break;
      }
    case INS_MODE_IU:
      {
        i = cgIns_NewU (o, arg1);
        break;
      }
    case INS_MODE_IS:
      {
        i = cgIns_NewS (o, arg1);
        break;
      }
    case INS_MODE_IBA:
      {
        i = cgIns_NewAB (o, arg1, arg2);
        break;
      }
    default:
      break;
    }

  /* lineinfo */
  {
    if (lex->lastline > func->lastline)
      {
        __losu_mem_growvector (func->vm, f->lineinfo, f->nlineinfo, 2, int32_t,
                               vmOl_MaxInt32_t,
                               __config_losucore_errmsg_msgVectorOverflow);
        if (lex->lastline > func->lastline + 1)
          f->lineinfo[f->nlineinfo++]
              = -(lex->lastline - (func->lastline + 1));
        f->lineinfo[f->nlineinfo++] = func->pc;
        func->lastline = lex->lastline;
      }
  }

  __losu_mem_growvector (func->vm, func->fcode->code, func->pc, 1,
                         vmInstruction, vmOl_MaxInt32_t,
                         __config_losucore_errmsg_msgVectorOverflow);
  func->fcode->code[func->pc] = i;
  return func->pc++;
}

static void
__losuSyntaxCgenConcat (_syntaxFunc *func, int32_t *l1, int32_t l2)
{
  if (*l1 == NO_JUMP)
    *l1 = l2;
  else
    {
      int32_t l = *l1;
      while (1)
        {
          int32_t n = __losuSyntaxCgenGetJump (func, l);
          if (n == NO_JUMP)
            {
              __losuSyntaxCgenFixJump (func, l, l2);
              return;
            }
          l = n;
        }
    }
}

static int32_t
__losuSyntaxCgenJump (_syntaxFunc *func)
{
  int32_t j = __losuSyntaxCgenCodearg1 (func, INS_JMP, NO_JUMP);
  if (j == func->lasttarget)
    {
      __losuSyntaxCgenConcat (func, &j, func->jump);
      func->jump = NO_JUMP;
    }
  return j;
}
static void
__losuSyntaxCgenPalist (_syntaxFunc *func, int32_t list, int32_t tg)
{
  if (tg == func->lasttarget)
    __losuSyntaxCgenConcat (func, &func->jump, list);
  else
    __losuSyntaxCgenPlistfunc (func, list, tg, INS_END, 0);
}
static int32_t
__losuSyntaxCgenGetL (_syntaxFunc *func)
{
  if (func->pc != func->lasttarget)
    {
      int32_t ltg = func->lasttarget;
      func->lasttarget = func->pc;
      __losuSyntaxCgenPalist (func, func->jump, ltg);
      func->jump = NO_JUMP;
    }
  return func->pc;
}
static void
__losuSyntaxCgenGoT (_syntaxFunc *func, _syntaxExp *v, int32_t keep)
{
  __losuSyntaxCgenGo (func, v, 1, keep ? INS_JMPONF : INS_JMPF);
}
static void
__losuSyntaxCgenGoF (_syntaxFunc *func, _syntaxExp *v, int32_t keep)
{
  __losuSyntaxCgenGo (func, v, 0, keep ? INS_JMPONT : INS_JMPT);
}
static void
__losuSyntaxCgenTostack (_syntaxLex *lex, _syntaxExp *v, int32_t o)
{
#define codelab(func, op, arg)                                                \
  (__losuSyntaxCgenGetL (func), __losuSyntaxCgenCodearg1 (func, op, arg))

  _syntaxFunc *func = lex->fs;
  if (!__losuSyntaxCgenDischarge (func, v))
    {
      vmIns_OP pre = cgIns_GetOp (func->fcode->code[func->pc - 1]);
      if (!vmIns_Isjump (pre) && v->value._bool.f == NO_JUMP
          && v->value._bool.t == NO_JUMP)
        {
          if (o)
            __losuSyntaxCgenSetNcallr (func, 1);
        }
      else
        {
          int32_t final;
          int32_t j = NO_JUMP;
          int32_t pn = NO_JUMP;
          int32_t pl = NO_JUMP;
          if (vmIns_Isjump (pre)
              || __losuSyntaxCgenNeedval (func, v->value._bool.f, INS_JMPONF)
              || __losuSyntaxCgenNeedval (func, v->value._bool.t, INS_JMPONT))
            {
              if (vmIns_Isjump (pre))
                __losuSyntaxCgenConcat (func, &v->value._bool.t, func->pc - 1);
              else
                {
                  j = codelab (func, INS_JMP, NO_JUMP);
                  __losuSyntaxCgenAdStack (func, 1);
                }
              pn = codelab (func, INS_PUSHNULLJMP, 0);
              pl = codelab (func, INS_PUSHNUM, 1);
              __losuSyntaxCgenPalist (func, j, __losuSyntaxCgenGetL (func));
            }
          final = __losuSyntaxCgenGetL (func);
          __losuSyntaxCgenPlistfunc (func, v->value._bool.f, pn, INS_JMPONF,
                                     final);
          __losuSyntaxCgenPlistfunc (func, v->value._bool.t, pl, INS_JMPONT,
                                     final);
          v->value._bool.f = v->value._bool.t = NO_JUMP;
        }
    }

#undef codelab
}
static void
__losuSyntaxCgenAdStack (_syntaxFunc *func, int32_t n)
{
  if (n > 0)
    __losuSyntaxCgenCodearg1 (func, INS_POP, n);
  else
    __losuSyntaxCgenCodearg1 (func, INS_PUSHNULL, -n);
}
static void
__losuSyntaxCgenSetVar (_syntaxLex *lex, _syntaxExp *var)
{
  _syntaxFunc *func = lex->fs;
  switch (var->type)
    {
    case VL:
      __losuSyntaxCgenCodearg1 (func, INS_SETLOCAL, var->value.index);
      break;
    case VG:
      __losuSyntaxCgenCodearg1 (func, INS_SETGLOBAL, var->value.index);
      break;
    case VI:
      __losuSyntaxCgenCodearg2 (func, INS_SETUNIT, 3, 3);
      break;
    default:
      break;
    }
}
static _l_bool
__losuSyntaxCgenIsopen (_syntaxFunc *func)
{
  vmInstruction i = func->pc > func->lasttarget
                        ? func->fcode->code[func->pc - 1]
                        : ((vmInstruction)INS_END);
  if (cgIns_GetOp (i) == INS_CALL && cgIns_GetB (i) == 255)
    return 1;
  else
    return 0;
}
static void
__losuSyntaxCgenSetNcallr (_syntaxFunc *func, int32_t nres)
{
  if (__losuSyntaxCgenIsopen (func))
    {
      cgIns_SetB (func->fcode->code[func->pc - 1], nres);
      __losuSyntaxCgenDtStack (func, nres);
    }
}
static void
__losuSyntaxCgenNumber (_syntaxFunc *func, _l_number n)
{
  _inlineScode *fc = func->fcode;
  int32_t c = fc->nlcnum;
  /*
    int lim = c < LOOKBACKNUMS ? 0 : c - LOOKBACKNUMS;
    while (--c >= lim)
  */
  int32_t lim = c < vmOl_MaxNumberRef ? 0 : c - vmOl_MaxNumberRef;
  while (--c >= lim)
    if (fc->lcnum[c] == n)
      {
        __losuSyntaxCgenCodearg1 (func, INS_PUSHNUM, c);
        return;
      }

  __losu_mem_growvector (func->vm, fc->lcnum, fc->nlcnum, 1, _l_number,
                         vmIns_MaxU,
                         __config_losucore_errmsg_msgVectorOverflow);
  c = fc->nlcnum++;
  fc->lcnum[c] = n;
  __losuSyntaxCgenCodearg1 (func, INS_PUSHNUM, c);
}
static void
__losuSyntaxCgenDtStack (_syntaxFunc *func, int32_t dt)
{
  func->stacklevel += dt;
  if (func->stacklevel > func->fcode->maxstacksize)
    {
      if (func->stacklevel > vmOl_MaxStack)
        __losuSyntaxError (func->lexer,
                           __config_losucore_errmsg_msgTooComplexExp);
      func->fcode->maxstacksize = func->stacklevel;
    }
}
static void
__losuSyntaxCgenPrefix (_syntaxLex *lex, vmIns_UnOp op, _syntaxExp *v)
{
#define swap(v)                                                               \
  {                                                                           \
    int32_t tmp = v->value._bool.f;                                           \
    v->value._bool.f = v->value._bool.t;                                      \
    v->value._bool.t = tmp;                                                   \
  }

  _syntaxFunc *func = lex->fs;
  if (op == INS_UNOP_NEG)
    {
      __losuSyntaxCgenTostack (lex, v, 1);
      __losuSyntaxCgenCodearg0 (func, INS_NEG);
    }
  else
    {
      vmInstruction *pre;
      __losuSyntaxCgenDischarge (func, v);
      if (v->value._bool.t == NO_JUMP && v->value._bool.f == NO_JUMP)
        __losuSyntaxCgenSetNcallr (func, 1);

      pre = &(func->fcode->code[func->pc - 1]);
      if (vmIns_Isjump (cgIns_GetOp ((*pre))))
        cgIns_SetOp ((*pre),
                     __losuSyntaxCgenJumpInvert (cgIns_GetOp ((*pre))));
      else
        __losuSyntaxCgenCodearg0 (func, INS_NOT);

      swap (v);
    }

#undef swap
}
static void
__losuSyntaxCgenInfix (_syntaxLex *lex, vmIns_BinOp op, _syntaxExp *v)
{
  _syntaxFunc *func = lex->fs;
  switch (op)
    {
    case INS_BINOP_AND:
      {
        __losuSyntaxCgenGoT (func, v, 1);
        break;
      }
    case INS_BINOP_OR:
      {
        __losuSyntaxCgenGoF (func, v, 1);
        break;
      }
    default:
      {
        __losuSyntaxCgenTostack (lex, v, 1);
        break;
      }
    }
}
static void
__losuSyntaxCgenPosfix (_syntaxLex *lex, vmIns_BinOp op, _syntaxExp *v1,
                        _syntaxExp *v2)
{
  _syntaxFunc *func = lex->fs;
  switch (op)
    {
    case INS_BINOP_AND:
      {
        __losuSyntaxCgenDischarge (func, v2);
        if (v2->value._bool.t == NO_JUMP && v2->value._bool.f == NO_JUMP)
          __losuSyntaxCgenSetNcallr (func, 1);
        v1->value._bool.t = v2->value._bool.t;
        __losuSyntaxCgenConcat (func, &v1->value._bool.f, v2->value._bool.f);
        break;
      }
    case INS_BINOP_OR:
      {
        __losuSyntaxCgenDischarge (func, v2);
        if (v2->value._bool.t == NO_JUMP && v2->value._bool.f == NO_JUMP)
          __losuSyntaxCgenSetNcallr (func, 1);
        v1->value._bool.f = v2->value._bool.f;
        __losuSyntaxCgenConcat (func, &v1->value._bool.t, v2->value._bool.t);
        break;
      }
    default:
      {
        __losuSyntaxCgenTostack (lex, v2, 1);
        __losuSyntaxCgenCodearg1 (func, _alops[op].op, _alops[op].arg);
        break;
      }
    }
}

static int32_t
__losuSyntaxCgenGetJump (_syntaxFunc *func, int32_t pc)
{
  int32_t o = cgIns_GetS (func->fcode->code[pc]);
  if (o == NO_JUMP)
    return NO_JUMP;
  else
    return (pc + 1) + o;
}
static void
__losuSyntaxCgenFixJump (_syntaxFunc *func, int32_t pc, int32_t dt)
{
  vmInstruction *jmp = &func->fcode->code[pc];
  if (dt == NO_JUMP)
    cgIns_SetS ((*jmp), NO_JUMP);
  else
    {
      int32_t o = dt - (pc + 1);
      if (abs (o) > vmIns_MaxS)
        __losuSyntaxError (func->lexer,
                           __config_losucore_errmsg_msgInvalidJump);
      cgIns_SetS ((*jmp), o);
    }
}
static void
__losuSyntaxCgenPlistfunc (_syntaxFunc *func, int32_t list, int32_t tg,
                           vmIns_OP ins, int32_t instg)
{
  vmInstruction *code = func->fcode->code;
  while (list != NO_JUMP)
    {
      int32_t next = __losuSyntaxCgenGetJump (func, list);
      vmInstruction *i = &code[list];
      vmIns_OP op = cgIns_GetOp ((*i));
      if (op == ins)
        __losuSyntaxCgenFixJump (func, list, instg);
      else
        {
          __losuSyntaxCgenFixJump (func, list, tg);
          if (op == INS_JMPONT)
            cgIns_SetOp ((*i), INS_JMPT);
          else if (op == INS_JMPONF)
            cgIns_SetOp ((*i), INS_JMPF);
        }
      list = next;
    }
}
static void
__losuSyntaxCgenGo (_syntaxFunc *func, _syntaxExp *v, int32_t inv,
                    vmIns_OP jump)
{
  int32_t prepc;
  vmInstruction *pre;
  int32_t *golist, *exitlist;
  if (!inv)
    {
      golist = &v->value._bool.f;
      exitlist = &v->value._bool.t;
    }
  else
    {
      golist = &v->value._bool.t;
      exitlist = &v->value._bool.f;
    }
  __losuSyntaxCgenDischarge (func, v);
  if (v->value._bool.t == NO_JUMP && v->value._bool.f == NO_JUMP)
    __losuSyntaxCgenSetNcallr (func, 1);
  prepc = func->pc - 1;
  pre = &func->fcode->code[prepc];
  if (!vmIns_Isjump (cgIns_GetOp (*pre)))
    prepc = __losuSyntaxCgenCodearg1 (func, jump, NO_JUMP);
  else if (inv)
    cgIns_SetOp (*pre, __losuSyntaxCgenJumpInvert (cgIns_GetOp (*pre)));
  __losuSyntaxCgenConcat (func, exitlist, prepc);
  __losuSyntaxCgenPalist (func, *golist, __losuSyntaxCgenGetL (func));
  *golist = NO_JUMP;
}
static _l_bool
__losuSyntaxCgenDischarge (_syntaxFunc *func, _syntaxExp *v)
{
  switch (v->type)
    {
    case VL:
      {
        __losuSyntaxCgenCodearg1 (func, INS_GETLOCAL, v->value.index);
        break;
      }
    case VG:
      {
        __losuSyntaxCgenCodearg1 (func, INS_GETGLOBAL, v->value.index);
        break;
      }
    case VI:
      {
        __losuSyntaxCgenCodearg0 (func, INS_GETUNIT);
        break;
      }
    case VE:
      {
        return 0;
      }
    default:
      break;
    }
  v->type = VE;
  v->value._bool.t = v->value._bool.f = NO_JUMP;
  return 1;
}
static _l_bool
__losuSyntaxCgenNeedval (_syntaxFunc *func, int32_t l, vmIns_OP op)
{
  for (; l != NO_JUMP; l = __losuSyntaxCgenGetJump (func, l))
    if (cgIns_GetOp (func->fcode->code[l]) != op)
      return 1;
  return 0;
}
static vmIns_OP
__losuSyntaxCgenJumpInvert (vmIns_OP op)
{
  switch (op)
    {
    case INS_JMPNE:
      return INS_JMPEQ;
    case INS_JMPEQ:
      return INS_JMPNE;

    case INS_JMPLT:
      return INS_JMPGE;
    case INS_JMPLE:
      return INS_JMPGT;

    case INS_JMPGT:
      return INS_JMPLE;
    case INS_JMPGE:
      return INS_JMPLT;

    case INS_JMPT:
    case INS_JMPONT:
      return INS_JMPF;

    case INS_JMPF:
    case INS_JMPONF:
      return INS_JMPT;

    default:
      return INS_END;
    }
}

#undef NO_JUMP

#endif /* define_source_losusyntax_codegen */

#ifndef define_source_losusyntax_irload
#define define_source_losusyntax_irload

#define EOZ (-1)

static _l_bool __losuSyntaxIrLoadHead (LosuVm *vm, _syntaxIO *io);
static _inlineScode *__losuSyntaxIrLoadFunc (LosuVm *vm, _syntaxIO *io,
                                             _l_bool diff);
static _inlineString *__losuSyntaxIrLoadString (LosuVm *vm, _syntaxIO *io,
                                                _l_bool diff);
/* static _l_number __losuSyntaxIrLoadNumber (LosuVm *vm, _syntaxIO *io,
                                           _l_bool diff); */
static int32_t __losuSyntaxIrLoadInt32 (LosuVm *vm, _syntaxIO *io,
                                        _l_bool diff);
static size_t __losuSyntaxIrLoadSizet (LosuVm *vm, _syntaxIO *io,
                                       _l_bool diff);

static void __losuSyntaxIrLoadConst (LosuVm *vm, _inlineScode *fs,
                                     _syntaxIO *io, _l_bool diff);
static void __losuSyntaxIrLoadIns (LosuVm *vm, _inlineScode *fs, _syntaxIO *io,
                                   _l_bool diff);
static void __losuSyntaxIrLoadLine (LosuVm *vm, _inlineScode *fs,
                                    _syntaxIO *io, _l_bool diff);
static void __losuSyntaxIrLoadLcvar (LosuVm *vm, _inlineScode *fs,
                                     _syntaxIO *io, _l_bool diff);

static int32_t __losuSyntaxIrLoadByte (LosuVm *vm, _syntaxIO *io);
static void __losuSyntaxIrLoadBlock (LosuVm *vm, void *b, size_t size,
                                     _syntaxIO *io, _l_bool diff);
static void __losuSyntaxIrLoadVector (LosuVm *vm, void *b, int m, size_t size,
                                      _syntaxIO *io, _l_bool diff);

static uint8_t __losuSyntaxIrIOgetc (LosuVm *vm, _syntaxIO *io);

static void __losuSyntaxIrError (LosuVm *vm, const char *msg, ...);

_inlineScode *
__losu_syntaxIrload_load (LosuVm *vm, _syntaxIO *io)
{
  _inlineScode *fs = NULL;
  /* load magic */
  int32_t n = __losu_syntaxIO_getint32 (io);
  if (n == 0)
    fs = __losuSyntaxIrLoadFunc (vm, io, __losuSyntaxIrLoadHead (vm, io));
  else
    __losuSyntaxIrError (vm,
                         __config_losucore_errmsg_msgIllegalBytecodeFormat);
  n = __losu_syntaxIO_getint32 (io);
  if (n != EOZ)
    __losuSyntaxIrError (vm,
                         __config_losucore_errmsg_msgIllegalBytecodeFormat);
  return fs;
}

static _l_bool
__losuSyntaxIrLoadHead (LosuVm *vm, _syntaxIO *io)
{
  int32_t _diff = 1;
  uint8_t _diffc = *(uint8_t *)(&_diff);

  /* Load Endianness */
  _l_bool diff = (_diffc != __losuSyntaxIrIOgetc (vm, io));

  /* Load Version */
  {
    _l_size_t v = __losuSyntaxIrLoadSizet (vm, io, diff);
    if (v != LosuVersionNum)
      __losuSyntaxIrError (
          vm, __config_losucore_errmsg_msgInvalidVmBytecodeVersion,
          LosuVersionNum, v);
  }

  /* Load Vm-bitsize  */
  {
    int32_t fbit; /* file bit size */
    fbit = __losuSyntaxIrIOgetc (vm, io);
    if (fbit != sizeof (vmInstruction))
      __losuSyntaxIrError (vm, __config_losucore_errmsg_msgInvalidVmInsSize,
                           fbit * 8, sizeof (vmInstruction) * 8);

    return diff;
  }
}

static _inlineScode *
__losuSyntaxIrLoadFunc (LosuVm *vm, _syntaxIO *io, _l_bool diff)
{
  _inlineScode *fc = __losu_objFunc_scodeNew (vm);
  fc->src = __losuSyntaxIrLoadString (vm, io, diff);
  fc->defedline = __losuSyntaxIrLoadInt32 (vm, io, diff);
  fc->narg = __losuSyntaxIrLoadInt32 (vm, io, diff);
  fc->isVarg = __losuSyntaxIrLoadByte (vm, io);
  fc->maxstacksize = __losuSyntaxIrLoadInt32 (vm, io, diff);

  __losuSyntaxIrLoadLcvar (vm, fc, io, diff);
  __losuSyntaxIrLoadLine (vm, fc, io, diff);
  __losuSyntaxIrLoadConst (vm, fc, io, diff);
  __losuSyntaxIrLoadIns (vm, fc, io, diff);

  return fc;
}

static _inlineString *
__losuSyntaxIrLoadString (LosuVm *vm, _syntaxIO *io, _l_bool diff)
{
  size_t s = __losuSyntaxIrLoadSizet (vm, io, diff);
  if (s == 0)
    return NULL;
  else
    {
      if (s > vm->nbufftmp)
        {
          __losu_mem_reallocvector (vm, vm->bufftmp, s, unsigned char);
          vm->nblocks += (s - vm->nbufftmp) * sizeof (unsigned char);
          vm->nbufftmp = s;
          memset (vm->bufftmp, 0, s);
        }
      __losuSyntaxIrLoadBlock (vm, vm->bufftmp, s, io, 0);
      return __losu_objString_newstr (vm, (const char *)vm->bufftmp, s - 1);
    }
}

/* static _l_number
__losuSyntaxIrLoadNumber (LosuVm *vm, _syntaxIO *io, _l_bool diff)
{
  _l_number n;
  __losuSyntaxIrLoadBlock (vm, &n, sizeof (_l_number), io, diff);
  return n;
} */

static int32_t
__losuSyntaxIrLoadInt32 (LosuVm *vm, _syntaxIO *io, _l_bool diff)
{
  int32_t n;
  __losuSyntaxIrLoadBlock (vm, &n, sizeof (int32_t), io, diff);
  return n;
}

static size_t
__losuSyntaxIrLoadSizet (LosuVm *vm, _syntaxIO *io, _l_bool diff)
{
  size_t n = 0;
  _l_size_t t;
  __losuSyntaxIrLoadBlock (vm, &t, sizeof (_l_size_t), io, diff);
  n = t;
  return n;
}

static void
__losuSyntaxIrLoadConst (LosuVm *vm, _inlineScode *fs, _syntaxIO *io,
                         _l_bool diff)
{
  /* load string */
  fs->nlcstr = __losuSyntaxIrLoadInt32 (vm, io, diff);
  fs->lcstr = __losu_mem_newvector (vm, fs->nlcstr, _inlineString *);
  for (int32_t i = 0; i < fs->nlcstr; i++)
    fs->lcstr[i] = __losuSyntaxIrLoadString (vm, io, diff);

  /* load num */
  fs->nlcnum = __losuSyntaxIrLoadInt32 (vm, io, diff);
  fs->lcnum = __losu_mem_newvector (vm, fs->nlcnum, _l_number);
  __losuSyntaxIrLoadVector (vm, fs->lcnum, fs->nlcnum, sizeof (_l_number), io,
                            diff);

  /* load func */
  fs->nlcscode = __losuSyntaxIrLoadInt32 (vm, io, diff);
  fs->lcscode = __losu_mem_newvector (vm, fs->nlcscode, _inlineScode *);
  for (int32_t i = 0; i < fs->nlcscode; i++)
    fs->lcscode[i] = __losuSyntaxIrLoadFunc (vm, io, diff);
}

static void
__losuSyntaxIrLoadIns (LosuVm *vm, _inlineScode *fs, _syntaxIO *io,
                       _l_bool diff)
{
  int32_t n = __losuSyntaxIrLoadInt32 (vm, io, diff);
  fs->code = __losu_mem_newvector (vm, n, vmInstruction);
  __losuSyntaxIrLoadVector (vm, fs->code, n, sizeof (vmInstruction), io, diff);
  fs->ncode = n;
  vm->nblocks += (sizeof (_inlineScode) + fs->nlcnum * sizeof (_l_number)
                  + fs->nlcstr * sizeof (_inlineString *)
                  + fs->nlcscode * sizeof (_inlineScode *)
                  + fs->ncode * sizeof (vmInstruction)
                  + fs->nlocalvar * sizeof (_inlineLocalvar)
                  + fs->nlineinfo * sizeof (int32_t));
}

static void
__losuSyntaxIrLoadLine (LosuVm *vm, _inlineScode *fs, _syntaxIO *io,
                        _l_bool diff)
{
  fs->nlineinfo = __losuSyntaxIrLoadInt32 (vm, io, diff);
  fs->lineinfo = __losu_mem_newvector (vm, fs->nlineinfo, int32_t);
  __losuSyntaxIrLoadVector (vm, fs->lineinfo, fs->nlineinfo, sizeof (int32_t),
                            io, diff);
}

static void
__losuSyntaxIrLoadLcvar (LosuVm *vm, _inlineScode *fs, _syntaxIO *io,
                         _l_bool diff)
{
  fs->nlocalvar = __losuSyntaxIrLoadInt32 (vm, io, diff);
  fs->localvar = __losu_mem_newvector (vm, fs->nlocalvar, _inlineLocalvar);
  for (int32_t i = 0; i < fs->nlocalvar; i++)
    {
      fs->localvar[i].name = __losuSyntaxIrLoadString (vm, io, diff);
      fs->localvar[i].startpc = __losuSyntaxIrLoadInt32 (vm, io, diff);
      fs->localvar[i].endpc = __losuSyntaxIrLoadInt32 (vm, io, diff);
    }
}

static int32_t
__losuSyntaxIrLoadByte (LosuVm *vm, _syntaxIO *io)
{
  return (int32_t)__losuSyntaxIrIOgetc (vm, io);
}

static void
__losuSyntaxIrLoadBlock (LosuVm *vm, void *b, size_t size, _syntaxIO *io,
                         _l_bool diff)
{
  if (diff)
    {
      uint8_t *p = (uint8_t *)(b + size - 1);
      while (size--)
        *(p--) = __losuSyntaxIrIOgetc (vm, io);
    }
  else
    {
      uint8_t *p = (uint8_t *)b;
      while (size--)
        *(p++) = __losuSyntaxIrIOgetc (vm, io);
    }
}
static void
__losuSyntaxIrLoadVector (LosuVm *vm, void *b, int m, size_t size,
                          _syntaxIO *io, _l_bool diff)
{
  if (diff)
    {
      uint8_t *p = (uint8_t *)(b + m * size - 1);
      while (m--)
        {
          __losuSyntaxIrLoadBlock (vm, p, size, io, diff);
          p -= size;
        }
    }
  else
    {
      uint8_t *p = (uint8_t *)b;
      while (m--)
        {
          __losuSyntaxIrLoadBlock (vm, p, size, io, diff);
          p += size;
        }
    }
}

static uint8_t
__losuSyntaxIrIOgetc (LosuVm *vm, _syntaxIO *io)
{
  int16_t c = __losu_syntaxIO_getc (io);

  if (c == EOZ)
    __losuSyntaxIrError (vm,
                         __config_losucore_errmsg_msgIllegalBytecodeFormat);
  return (uint8_t)c;
}

static void
__losuSyntaxIrError (LosuVm *vm, const char *msg, ...)
{
  memset (vm->staticbuff, 0, sizeof (vm->staticbuff));
  va_list ap;
  va_start (ap, msg);
  vsprintf ((char *)(vm->staticbuff), msg, ap);
  fprintf (stderr, "Bytecode Error: %s\n at '%s'\n", vm->staticbuff,
           vm->name != NULL ? vm->name : "<unknown>");
  va_end (ap);
  __losu_vmHeap_break (vm, LosuErrorCode_Syntax);
}

#undef EOZ

#endif
